From fe8ca4430327974ba39f47c331edabc7fad60748 Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Sat, 12 Feb 2022 16:06:52 +0530 Subject: [PATCH 01/21] implemented add token for queue store --- internal/datastore/mongo_store.go | 19 +++++++++++++++---- internal/datastore/store.go | 6 +++--- internal/models/db/token.go | 3 +++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/internal/datastore/mongo_store.go b/internal/datastore/mongo_store.go index 116854a..23e887c 100644 --- a/internal/datastore/mongo_store.go +++ b/internal/datastore/mongo_store.go @@ -114,14 +114,25 @@ func (mongodb MongoDB) DeleteQueue(id db.QueueId) error { return nil } -func (mongodb MongoDB) AddTokenToQueue(db.QueueId, db.Token) { - panic("Not implemented") +func (mongodb MongoDB) AddTokenToQueue(id db.QueueId, token db.Token) (db.TokenId, error) { + token.Id = "" + token.QueueId = id + + result, err := mongodb.Token.InsertOne(context.TODO(), token) + + if err != nil { + return token.Id, err + } + + stringId := result.InsertedID.(primitive.ObjectID).Hex() + + return db.TokenId(stringId), nil } -func (mongodb MongoDB) ReadToken(db.TokenId) { +func (mongodb MongoDB) ReadToken(db.TokenId) (db.Token, error) { panic("Not implemented") } -func (mongodb MongoDB) RemoveToken(db.TokenId) { +func (mongodb MongoDB) RemoveToken(db.TokenId) error { panic("Not implemented") } diff --git a/internal/datastore/store.go b/internal/datastore/store.go index b409e85..f6d4a80 100644 --- a/internal/datastore/store.go +++ b/internal/datastore/store.go @@ -18,13 +18,13 @@ type QueueStore interface { DeleteQueue(db.QueueId) error // Add a new token to the queue. - AddTokenToQueue(db.QueueId, db.Token) + AddTokenToQueue(db.QueueId, db.Token) (db.TokenId, error) // Read token by id. - ReadToken(db.TokenId) + ReadToken(db.TokenId) (db.Token, error) // Delete token - RemoveToken(db.TokenId) + RemoveToken(db.TokenId) error } var Store QueueStore = NewMongoDB() diff --git a/internal/models/db/token.go b/internal/models/db/token.go index cee7cc3..cc9ef2f 100644 --- a/internal/models/db/token.go +++ b/internal/models/db/token.go @@ -11,6 +11,9 @@ type Token struct { // Unique ID for the token. Id TokenId + // QueueId of the Queue that this token belongs to + QueueId QueueId + // Name of the token, typically name of the person to whom the token was // issued. Name string From 823cefede21e1fbe47319e65b73ae812b060f127 Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Sat, 12 Feb 2022 16:07:09 +0530 Subject: [PATCH 02/21] implemented create token route --- internal/handler/token.go | 52 ++++++++++++++++++++++++++++++++++++ internal/models/api/token.go | 52 ++++++++++++++++++++++++++++++++++++ internal/mux/mux.go | 6 +++++ 3 files changed, 110 insertions(+) create mode 100644 internal/handler/token.go create mode 100644 internal/models/api/token.go diff --git a/internal/handler/token.go b/internal/handler/token.go new file mode 100644 index 0000000..a3efb67 --- /dev/null +++ b/internal/handler/token.go @@ -0,0 +1,52 @@ +package handler + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "time" + + "github.com/SimplQ/simplQ-golang/internal/datastore" + "github.com/SimplQ/simplQ-golang/internal/models/api" + "github.com/SimplQ/simplQ-golang/internal/models/db" +) + +func CreateToken(w http.ResponseWriter, r *http.Request) { + decoder := json.NewDecoder(r.Body) + + var tokenRequest api.AddTokenRequest + err := decoder.Decode(&tokenRequest) + + if err != nil { + http.Error(w, fmt.Sprint(err), http.StatusBadRequest) + return + } + + validationErr, ok := tokenRequest.Validate() + + if !ok { + http.Error(w, validationErr.Message, http.StatusBadRequest) + return + } + + token := db.Token { + Name: tokenRequest.Name, + ContactNumber: tokenRequest.ContactNumber, + EmailId: tokenRequest.EmailId, + IsDeleted: false, + NotifiedCount: 0, + CreationTime: time.Now(), + } + + insertedId, err := datastore.Store.AddTokenToQueue(tokenRequest.QueueId, token) + + if err != nil { + http.Error(w, fmt.Sprint(err), http.StatusInternalServerError) + return + } + + log.Printf("Inserted %s", insertedId) + w.WriteHeader(http.StatusCreated) + fmt.Fprintf(w, "Token created with Id: %s", insertedId) +} diff --git a/internal/models/api/token.go b/internal/models/api/token.go new file mode 100644 index 0000000..dfde0e9 --- /dev/null +++ b/internal/models/api/token.go @@ -0,0 +1,52 @@ +// Package internal/models/api defines models to be used for API requests. +package api + +import ( + "fmt" + "strconv" + + "github.com/SimplQ/simplQ-golang/internal/models/db" +) + +// AddTokenRequest is a model to structure an add token request. +// +// Members +// +// QueueId - QueueId of the queue that this token is to be added to +// Name - Name of the token, typically name of the person whom the +// token was issued to. +// ContactNumber - Contact Number. +// EmailId - Optional. Email ID if the queue collects email ID of users. +type AddTokenRequest struct { + QueueId db.QueueId + Name string + ContactNumber string + EmailId string +} + +// AddTokenResponse is a model to structure the response of an add token request. +type AddTokenResponse db.TokenId + +func (req AddTokenRequest) Validate() (ValidationError, bool) { + if len(req.Name) < MIN_LENGTH || len(req.Name) > MAX_LENGTH { + message := fmt.Sprintf("Token name length should be greater than %d characters and less than %d characters", MIN_LENGTH, MAX_LENGTH) + return ValidationError { + Field: "Name", + Message: message, + }, false + } else if len(req.ContactNumber) != 10 { + message := fmt.Sprintf("Contact number should be 10 digits") + return ValidationError { + Field: "ContactNumber", + Message: message, + }, false + } else if _, err := strconv.Atoi(req.ContactNumber); err != nil { + message := fmt.Sprintf("Contact number should only consist of digits") + return ValidationError { + Field: "ContactNumber", + Message: message, + }, false + } else { + return ValidationError{}, true + } +} diff --git a/internal/mux/mux.go b/internal/mux/mux.go index e62e488..aa3b6ef 100644 --- a/internal/mux/mux.go +++ b/internal/mux/mux.go @@ -33,5 +33,11 @@ func InitalizeRoutes() chi.Router { r.Delete("/", handler.DeleteQueue) // DELETE /queue/123 }) }) + + // Routes for "token" resource + r.Route("/token", func(r chi.Router) { + // Add new token to queue + r.Post("/", handler.CreateToken) + }) return r } From 42120c2c45b33d4efc19e0eb6c0feea11f9f4eea Mon Sep 17 00:00:00 2001 From: Lint Action Date: Sat, 12 Feb 2022 10:37:28 +0000 Subject: [PATCH 03/21] Fix code style issues with gofmt --- internal/datastore/mongo_store.go | 8 ++--- internal/handler/token.go | 50 +++++++++++++++---------------- internal/models/api/token.go | 50 +++++++++++++++---------------- internal/models/db/token.go | 4 +-- internal/mux/mux.go | 10 +++---- 5 files changed, 61 insertions(+), 61 deletions(-) diff --git a/internal/datastore/mongo_store.go b/internal/datastore/mongo_store.go index 23e887c..a169a9c 100644 --- a/internal/datastore/mongo_store.go +++ b/internal/datastore/mongo_store.go @@ -115,10 +115,10 @@ func (mongodb MongoDB) DeleteQueue(id db.QueueId) error { } func (mongodb MongoDB) AddTokenToQueue(id db.QueueId, token db.Token) (db.TokenId, error) { - token.Id = "" - token.QueueId = id - - result, err := mongodb.Token.InsertOne(context.TODO(), token) + token.Id = "" + token.QueueId = id + + result, err := mongodb.Token.InsertOne(context.TODO(), token) if err != nil { return token.Id, err diff --git a/internal/handler/token.go b/internal/handler/token.go index a3efb67..f5d5ed5 100644 --- a/internal/handler/token.go +++ b/internal/handler/token.go @@ -13,40 +13,40 @@ import ( ) func CreateToken(w http.ResponseWriter, r *http.Request) { - decoder := json.NewDecoder(r.Body) + decoder := json.NewDecoder(r.Body) - var tokenRequest api.AddTokenRequest - err := decoder.Decode(&tokenRequest) + var tokenRequest api.AddTokenRequest + err := decoder.Decode(&tokenRequest) - if err != nil { - http.Error(w, fmt.Sprint(err), http.StatusBadRequest) - return - } + if err != nil { + http.Error(w, fmt.Sprint(err), http.StatusBadRequest) + return + } - validationErr, ok := tokenRequest.Validate() + validationErr, ok := tokenRequest.Validate() - if !ok { - http.Error(w, validationErr.Message, http.StatusBadRequest) - return - } + if !ok { + http.Error(w, validationErr.Message, http.StatusBadRequest) + return + } - token := db.Token { - Name: tokenRequest.Name, - ContactNumber: tokenRequest.ContactNumber, - EmailId: tokenRequest.EmailId, - IsDeleted: false, - NotifiedCount: 0, - CreationTime: time.Now(), - } + token := db.Token{ + Name: tokenRequest.Name, + ContactNumber: tokenRequest.ContactNumber, + EmailId: tokenRequest.EmailId, + IsDeleted: false, + NotifiedCount: 0, + CreationTime: time.Now(), + } - insertedId, err := datastore.Store.AddTokenToQueue(tokenRequest.QueueId, token) + insertedId, err := datastore.Store.AddTokenToQueue(tokenRequest.QueueId, token) - if err != nil { + if err != nil { http.Error(w, fmt.Sprint(err), http.StatusInternalServerError) return - } - - log.Printf("Inserted %s", insertedId) + } + + log.Printf("Inserted %s", insertedId) w.WriteHeader(http.StatusCreated) fmt.Fprintf(w, "Token created with Id: %s", insertedId) } diff --git a/internal/models/api/token.go b/internal/models/api/token.go index dfde0e9..fd63703 100644 --- a/internal/models/api/token.go +++ b/internal/models/api/token.go @@ -18,35 +18,35 @@ import ( // ContactNumber - Contact Number. // EmailId - Optional. Email ID if the queue collects email ID of users. type AddTokenRequest struct { - QueueId db.QueueId - Name string - ContactNumber string - EmailId string + QueueId db.QueueId + Name string + ContactNumber string + EmailId string } // AddTokenResponse is a model to structure the response of an add token request. type AddTokenResponse db.TokenId func (req AddTokenRequest) Validate() (ValidationError, bool) { - if len(req.Name) < MIN_LENGTH || len(req.Name) > MAX_LENGTH { - message := fmt.Sprintf("Token name length should be greater than %d characters and less than %d characters", MIN_LENGTH, MAX_LENGTH) - return ValidationError { - Field: "Name", - Message: message, - }, false - } else if len(req.ContactNumber) != 10 { - message := fmt.Sprintf("Contact number should be 10 digits") - return ValidationError { - Field: "ContactNumber", - Message: message, - }, false - } else if _, err := strconv.Atoi(req.ContactNumber); err != nil { - message := fmt.Sprintf("Contact number should only consist of digits") - return ValidationError { - Field: "ContactNumber", - Message: message, - }, false - } else { - return ValidationError{}, true - } + if len(req.Name) < MIN_LENGTH || len(req.Name) > MAX_LENGTH { + message := fmt.Sprintf("Token name length should be greater than %d characters and less than %d characters", MIN_LENGTH, MAX_LENGTH) + return ValidationError{ + Field: "Name", + Message: message, + }, false + } else if len(req.ContactNumber) != 10 { + message := fmt.Sprintf("Contact number should be 10 digits") + return ValidationError{ + Field: "ContactNumber", + Message: message, + }, false + } else if _, err := strconv.Atoi(req.ContactNumber); err != nil { + message := fmt.Sprintf("Contact number should only consist of digits") + return ValidationError{ + Field: "ContactNumber", + Message: message, + }, false + } else { + return ValidationError{}, true + } } diff --git a/internal/models/db/token.go b/internal/models/db/token.go index cc9ef2f..1a99041 100644 --- a/internal/models/db/token.go +++ b/internal/models/db/token.go @@ -11,8 +11,8 @@ type Token struct { // Unique ID for the token. Id TokenId - // QueueId of the Queue that this token belongs to - QueueId QueueId + // QueueId of the Queue that this token belongs to + QueueId QueueId // Name of the token, typically name of the person to whom the token was // issued. diff --git a/internal/mux/mux.go b/internal/mux/mux.go index aa3b6ef..186bee1 100644 --- a/internal/mux/mux.go +++ b/internal/mux/mux.go @@ -34,10 +34,10 @@ func InitalizeRoutes() chi.Router { }) }) - // Routes for "token" resource - r.Route("/token", func(r chi.Router) { - // Add new token to queue - r.Post("/", handler.CreateToken) - }) + // Routes for "token" resource + r.Route("/token", func(r chi.Router) { + // Add new token to queue + r.Post("/", handler.CreateToken) + }) return r } From 4ec0ec91f34564f3f6ddcb5816ae5689a2dfd700 Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Mon, 14 Feb 2022 13:17:49 +0530 Subject: [PATCH 04/21] read tokens in the queue in readqueue --- internal/datastore/mongo_store.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/internal/datastore/mongo_store.go b/internal/datastore/mongo_store.go index 23e887c..2589070 100644 --- a/internal/datastore/mongo_store.go +++ b/internal/datastore/mongo_store.go @@ -75,6 +75,32 @@ func (mongodb MongoDB) ReadQueue(id db.QueueId) (db.Queue, error) { return result, err } + filterStage := bson.D{ + // queueid is a string this time + { Key: "$match", Value: bson.M{ "queueid": id} }, + } + + // sort tokens by ascending order of creation time + sortStage := bson.D{ + {Key: "$sort", Value: bson.D{ + {Key: "creationtime", Value: 1}, + {Key: "_id", Value: 1}, + }}, + } + + cursor, err := mongodb.Token.Aggregate(context.TODO(), mongo.Pipeline{filterStage, sortStage}) + + var tokens []db.Token + + if err = cursor.All(context.TODO(), &tokens); err != nil { + log.Fatal(err) + return result, err + } + + log.Printf("%d tokens in queue", len(tokens)) + + result.Tokens = tokens + return result, nil } From a44aee0490d1ba9179b63739995eb3caecd680bb Mon Sep 17 00:00:00 2001 From: Lint Action Date: Mon, 14 Feb 2022 07:49:37 +0000 Subject: [PATCH 05/21] Fix code style issues with gofmt --- internal/datastore/mongo_store.go | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/internal/datastore/mongo_store.go b/internal/datastore/mongo_store.go index 1cf4e85..c86c427 100644 --- a/internal/datastore/mongo_store.go +++ b/internal/datastore/mongo_store.go @@ -75,31 +75,31 @@ func (mongodb MongoDB) ReadQueue(id db.QueueId) (db.Queue, error) { return result, err } - filterStage := bson.D{ - // queueid is a string this time - { Key: "$match", Value: bson.M{ "queueid": id} }, - } + filterStage := bson.D{ + // queueid is a string this time + {Key: "$match", Value: bson.M{"queueid": id}}, + } - // sort tokens by ascending order of creation time - sortStage := bson.D{ - {Key: "$sort", Value: bson.D{ - {Key: "creationtime", Value: 1}, - {Key: "_id", Value: 1}, - }}, - } + // sort tokens by ascending order of creation time + sortStage := bson.D{ + {Key: "$sort", Value: bson.D{ + {Key: "creationtime", Value: 1}, + {Key: "_id", Value: 1}, + }}, + } - cursor, err := mongodb.Token.Aggregate(context.TODO(), mongo.Pipeline{filterStage, sortStage}) + cursor, err := mongodb.Token.Aggregate(context.TODO(), mongo.Pipeline{filterStage, sortStage}) - var tokens []db.Token + var tokens []db.Token - if err = cursor.All(context.TODO(), &tokens); err != nil { - log.Fatal(err) - return result, err - } + if err = cursor.All(context.TODO(), &tokens); err != nil { + log.Fatal(err) + return result, err + } - log.Printf("%d tokens in queue", len(tokens)) + log.Printf("%d tokens in queue", len(tokens)) - result.Tokens = tokens + result.Tokens = tokens return result, nil } From d477b238990bd3335d4d0dcc8e19329a439dbd55 Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Sat, 26 Feb 2022 17:43:06 +0530 Subject: [PATCH 06/21] implemented token number --- internal/datastore/mongo_store.go | 89 ++++++++++++++++++++++++++----- internal/models/db/token.go | 3 ++ 2 files changed, 80 insertions(+), 12 deletions(-) diff --git a/internal/datastore/mongo_store.go b/internal/datastore/mongo_store.go index 1cf4e85..f930a9d 100644 --- a/internal/datastore/mongo_store.go +++ b/internal/datastore/mongo_store.go @@ -5,6 +5,7 @@ import ( "errors" "log" "os" + "sync" "github.com/SimplQ/simplQ-golang/internal/models/db" @@ -21,6 +22,9 @@ type MongoDB struct { Token *mongo.Collection } +// Mutex to make sure only one add token request is running at a time +var queueMutex sync.Mutex + func NewMongoDB() *MongoDB { // Use local development mongodb instance if env variable not set uri := "mongodb://root:example@localhost:27017/?maxPoolSize=20&w=majority" @@ -75,20 +79,20 @@ func (mongodb MongoDB) ReadQueue(id db.QueueId) (db.Queue, error) { return result, err } - filterStage := bson.D{ + filter := bson.D{ // queueid is a string this time - { Key: "$match", Value: bson.M{ "queueid": id} }, + { Key: "queueid", Value: id }, } - // sort tokens by ascending order of creation time - sortStage := bson.D{ - {Key: "$sort", Value: bson.D{ - {Key: "creationtime", Value: 1}, - {Key: "_id", Value: 1}, - }}, + // sort tokens by ascending order of token number + sort := bson.D { + {Key: "tokennumber", Value: 1}, } - cursor, err := mongodb.Token.Aggregate(context.TODO(), mongo.Pipeline{filterStage, sortStage}) + findOptions := options.Find() + findOptions.SetSort(sort) + + cursor, err := mongodb.Token.Find(context.TODO(), filter, findOptions) var tokens []db.Token @@ -144,7 +148,23 @@ func (mongodb MongoDB) AddTokenToQueue(id db.QueueId, token db.Token) (db.TokenI token.Id = "" token.QueueId = id - result, err := mongodb.Token.InsertOne(context.TODO(), token) + // Lock queue to ensure 2 concurrent add tokens don't happen + queueMutex.Lock() + + // if there were 2 concurrent calls to this function, 2 tokens might get the same number + max, err := mongodb.GetMaxToken(id) + + if err != nil { + log.Fatal(err) + queueMutex.Unlock() + return token.Id, err + } + + token.TokenNumber = max + 1 + + result, err := mongodb.Token.InsertOne(context.TODO(), token) + + queueMutex.Unlock() if err != nil { return token.Id, err @@ -155,8 +175,53 @@ func (mongodb MongoDB) AddTokenToQueue(id db.QueueId, token db.Token) (db.TokenI return db.TokenId(stringId), nil } -func (mongodb MongoDB) ReadToken(db.TokenId) (db.Token, error) { - panic("Not implemented") +func (mongodb MongoDB) GetMaxToken(id db.QueueId) (uint32, error) { + filter := bson.D{ + // queueid is a string this time + { Key: "queueid", Value: id }, + } + + sort := bson.D { + {Key: "tokennumber", Value: -1}, + } + + findOptions := options.Find() + findOptions.SetSort(sort) + findOptions.SetLimit(1) + + cursor, err := mongodb.Token.Find(context.TODO(), filter, findOptions) + + if err != nil { + return 0, err + } + + var tokens []db.Token + + if err = cursor.All(context.TODO(), &tokens); err != nil { + log.Println(err) + return 0, err + } + + if len(tokens) <= 0 { + return 0, nil + } + + return tokens[0].TokenNumber, nil +} + +func (mongodb MongoDB) ReadToken(id db.TokenId) (db.Token, error) { + tokenId, _ := primitive.ObjectIDFromHex(string(id)) + + var result db.Token + + err := mongodb.Token.FindOne(context.TODO(), bson.M{"_id": tokenId}).Decode(&result) + + if err != nil { + log.Fatal(err) + return result, err + } + + return result, nil } func (mongodb MongoDB) RemoveToken(db.TokenId) error { diff --git a/internal/models/db/token.go b/internal/models/db/token.go index 1a99041..c07d52a 100644 --- a/internal/models/db/token.go +++ b/internal/models/db/token.go @@ -14,6 +14,9 @@ type Token struct { // QueueId of the Queue that this token belongs to QueueId QueueId + // Number representing the position of the token in the queue + TokenNumber uint32 + // Name of the token, typically name of the person to whom the token was // issued. Name string From 5299a8e3794fcebb4ecf86a78c6a2bb6e438b2cf Mon Sep 17 00:00:00 2001 From: Lint Action Date: Sat, 26 Feb 2022 12:16:29 +0000 Subject: [PATCH 07/21] Fix code style issues with gofmt --- internal/datastore/mongo_store.go | 114 +++++++++++++++--------------- internal/models/db/token.go | 4 +- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/internal/datastore/mongo_store.go b/internal/datastore/mongo_store.go index 6012ffb..8870180 100644 --- a/internal/datastore/mongo_store.go +++ b/internal/datastore/mongo_store.go @@ -5,7 +5,7 @@ import ( "errors" "log" "os" - "sync" + "sync" "github.com/SimplQ/simplQ-golang/internal/models/db" @@ -79,22 +79,22 @@ func (mongodb MongoDB) ReadQueue(id db.QueueId) (db.Queue, error) { return result, err } - filter := bson.D{ - // queueid is a string this time - { Key: "queueid", Value: id }, - } + filter := bson.D{ + // queueid is a string this time + {Key: "queueid", Value: id}, + } + + // sort tokens by ascending order of token number + sort := bson.D{ + {Key: "tokennumber", Value: 1}, + } - // sort tokens by ascending order of token number - sort := bson.D { - {Key: "tokennumber", Value: 1}, - } + findOptions := options.Find() + findOptions.SetSort(sort) - findOptions := options.Find() - findOptions.SetSort(sort) + cursor, err := mongodb.Token.Find(context.TODO(), filter, findOptions) - cursor, err := mongodb.Token.Find(context.TODO(), filter, findOptions) - - var tokens []db.Token + var tokens []db.Token if err = cursor.All(context.TODO(), &tokens); err != nil { log.Fatal(err) @@ -148,23 +148,23 @@ func (mongodb MongoDB) AddTokenToQueue(id db.QueueId, token db.Token) (db.TokenI token.Id = "" token.QueueId = id - // Lock queue to ensure 2 concurrent add tokens don't happen - queueMutex.Lock() + // Lock queue to ensure 2 concurrent add tokens don't happen + queueMutex.Lock() - // if there were 2 concurrent calls to this function, 2 tokens might get the same number - max, err := mongodb.GetMaxToken(id) + // if there were 2 concurrent calls to this function, 2 tokens might get the same number + max, err := mongodb.GetMaxToken(id) + + if err != nil { + log.Fatal(err) + queueMutex.Unlock() + return token.Id, err + } - if err != nil { - log.Fatal(err) - queueMutex.Unlock() - return token.Id, err - } + token.TokenNumber = max + 1 - token.TokenNumber = max + 1 - - result, err := mongodb.Token.InsertOne(context.TODO(), token) + result, err := mongodb.Token.InsertOne(context.TODO(), token) - queueMutex.Unlock() + queueMutex.Unlock() if err != nil { return token.Id, err @@ -176,52 +176,52 @@ func (mongodb MongoDB) AddTokenToQueue(id db.QueueId, token db.Token) (db.TokenI } func (mongodb MongoDB) GetMaxToken(id db.QueueId) (uint32, error) { - filter := bson.D{ - // queueid is a string this time - { Key: "queueid", Value: id }, - } + filter := bson.D{ + // queueid is a string this time + {Key: "queueid", Value: id}, + } - sort := bson.D { - {Key: "tokennumber", Value: -1}, - } + sort := bson.D{ + {Key: "tokennumber", Value: -1}, + } - findOptions := options.Find() - findOptions.SetSort(sort) - findOptions.SetLimit(1) + findOptions := options.Find() + findOptions.SetSort(sort) + findOptions.SetLimit(1) - cursor, err := mongodb.Token.Find(context.TODO(), filter, findOptions) + cursor, err := mongodb.Token.Find(context.TODO(), filter, findOptions) - if err != nil { - return 0, err - } + if err != nil { + return 0, err + } - var tokens []db.Token + var tokens []db.Token - if err = cursor.All(context.TODO(), &tokens); err != nil { - log.Println(err) - return 0, err - } + if err = cursor.All(context.TODO(), &tokens); err != nil { + log.Println(err) + return 0, err + } - if len(tokens) <= 0 { - return 0, nil - } + if len(tokens) <= 0 { + return 0, nil + } - return tokens[0].TokenNumber, nil + return tokens[0].TokenNumber, nil } func (mongodb MongoDB) ReadToken(id db.TokenId) (db.Token, error) { tokenId, _ := primitive.ObjectIDFromHex(string(id)) - var result db.Token + var result db.Token - err := mongodb.Token.FindOne(context.TODO(), bson.M{"_id": tokenId}).Decode(&result) + err := mongodb.Token.FindOne(context.TODO(), bson.M{"_id": tokenId}).Decode(&result) - if err != nil { - log.Fatal(err) - return result, err - } + if err != nil { + log.Fatal(err) + return result, err + } - return result, nil + return result, nil } func (mongodb MongoDB) RemoveToken(db.TokenId) error { diff --git a/internal/models/db/token.go b/internal/models/db/token.go index c07d52a..94c823f 100644 --- a/internal/models/db/token.go +++ b/internal/models/db/token.go @@ -14,8 +14,8 @@ type Token struct { // QueueId of the Queue that this token belongs to QueueId QueueId - // Number representing the position of the token in the queue - TokenNumber uint32 + // Number representing the position of the token in the queue + TokenNumber uint32 // Name of the token, typically name of the person to whom the token was // issued. From 085b8bd449abb533b42611ad69b6fc7387e7b146 Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Sat, 26 Feb 2022 18:01:25 +0530 Subject: [PATCH 08/21] added read token route --- internal/handler/token.go | 29 +++++++++++++++++++++++++++++ internal/mux/mux.go | 5 +++++ 2 files changed, 34 insertions(+) diff --git a/internal/handler/token.go b/internal/handler/token.go index f5d5ed5..a396343 100644 --- a/internal/handler/token.go +++ b/internal/handler/token.go @@ -1,6 +1,7 @@ package handler import ( + "context" "encoding/json" "fmt" "log" @@ -10,8 +11,11 @@ import ( "github.com/SimplQ/simplQ-golang/internal/datastore" "github.com/SimplQ/simplQ-golang/internal/models/api" "github.com/SimplQ/simplQ-golang/internal/models/db" + "github.com/go-chi/chi/v5" ) +const tokenId key = 0 + func CreateToken(w http.ResponseWriter, r *http.Request) { decoder := json.NewDecoder(r.Body) @@ -50,3 +54,28 @@ func CreateToken(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) fmt.Fprintf(w, "Token created with Id: %s", insertedId) } + +func GetToken(w http.ResponseWriter, r *http.Request) { + id := r.Context().Value(tokenId).(string) + + if id == "" { + http.Error(w, fmt.Sprintf("Invalid Id: %s", id), http.StatusBadRequest) + return + } + + token, err := datastore.Store.ReadToken(db.TokenId(id)) + + if err != nil { + http.Error(w, fmt.Sprint(err), http.StatusInternalServerError) + return + } + + json.NewEncoder(w).Encode(token) +} + +func TokenCtx(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), tokenId, chi.URLParam(r, "id")) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} diff --git a/internal/mux/mux.go b/internal/mux/mux.go index 186bee1..1798a33 100644 --- a/internal/mux/mux.go +++ b/internal/mux/mux.go @@ -38,6 +38,11 @@ func InitalizeRoutes() chi.Router { r.Route("/token", func(r chi.Router) { // Add new token to queue r.Post("/", handler.CreateToken) + + r.Route("/{id}", func(r chi.Router){ + r.Use(handler.TokenCtx) + r.Get("/", handler.GetToken) + }) }) return r } From 16e8417a7cb1d9b7ac099d1c833f5492e052478d Mon Sep 17 00:00:00 2001 From: Lint Action Date: Sat, 26 Feb 2022 12:32:16 +0000 Subject: [PATCH 09/21] Fix code style issues with gofmt --- internal/handler/token.go | 12 ++++++------ internal/mux/mux.go | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/handler/token.go b/internal/handler/token.go index a396343..f1d3fb8 100644 --- a/internal/handler/token.go +++ b/internal/handler/token.go @@ -57,20 +57,20 @@ func CreateToken(w http.ResponseWriter, r *http.Request) { func GetToken(w http.ResponseWriter, r *http.Request) { id := r.Context().Value(tokenId).(string) - - if id == "" { + + if id == "" { http.Error(w, fmt.Sprintf("Invalid Id: %s", id), http.StatusBadRequest) return } - token, err := datastore.Store.ReadToken(db.TokenId(id)) - - if err != nil { + token, err := datastore.Store.ReadToken(db.TokenId(id)) + + if err != nil { http.Error(w, fmt.Sprint(err), http.StatusInternalServerError) return } - json.NewEncoder(w).Encode(token) + json.NewEncoder(w).Encode(token) } func TokenCtx(next http.Handler) http.Handler { diff --git a/internal/mux/mux.go b/internal/mux/mux.go index 1798a33..a1796b4 100644 --- a/internal/mux/mux.go +++ b/internal/mux/mux.go @@ -39,10 +39,10 @@ func InitalizeRoutes() chi.Router { // Add new token to queue r.Post("/", handler.CreateToken) - r.Route("/{id}", func(r chi.Router){ - r.Use(handler.TokenCtx) - r.Get("/", handler.GetToken) - }) + r.Route("/{id}", func(r chi.Router) { + r.Use(handler.TokenCtx) + r.Get("/", handler.GetToken) + }) }) return r } From 534fd6ac568714a71b920b516d45122c4fb7c3c4 Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Sat, 26 Feb 2022 18:12:26 +0530 Subject: [PATCH 10/21] separated name length constants --- internal/models/api/queue.go | 8 ++++---- internal/models/api/token.go | 10 ++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/internal/models/api/queue.go b/internal/models/api/queue.go index 2b5e34d..c85b8d9 100644 --- a/internal/models/api/queue.go +++ b/internal/models/api/queue.go @@ -21,16 +21,16 @@ type CreateQueueRequest struct { type CreateQueueResponse db.Queue // Minimum length of a queue name. -const MIN_LENGTH = 4 +const MIN_LENGTH_QUEUE_NAME = 4 // Maximum length of a queue name. -const MAX_LENGTH = 20 +const MAX_LENGTH_QUEUE_NAME = 20 // Validate function for CreateQueueRequest validates if the queue name is within // the defined range. func (req CreateQueueRequest) Validate() (ValidationError, bool) { - if len(req.QueueName) < MIN_LENGTH || len(req.QueueName) > MAX_LENGTH { - message := fmt.Sprintf("Queue name length should be greater than %d characters and less than %d charaacters", MIN_LENGTH, MAX_LENGTH) + if len(req.QueueName) < MIN_LENGTH_QUEUE_NAME || len(req.QueueName) > MAX_LENGTH_QUEUE_NAME { + message := fmt.Sprintf("Queue name length should be greater than %d characters and less than %d charaacters", MIN_LENGTH_QUEUE_NAME, MAX_LENGTH_QUEUE_NAME) return ValidationError{ Field: "QueueName", Message: message, diff --git a/internal/models/api/token.go b/internal/models/api/token.go index fd63703..0058e5f 100644 --- a/internal/models/api/token.go +++ b/internal/models/api/token.go @@ -27,9 +27,15 @@ type AddTokenRequest struct { // AddTokenResponse is a model to structure the response of an add token request. type AddTokenResponse db.TokenId +// Minimum length of a token name +const MIN_LENGTH_TOKEN_NAME = 4 + +// Maximum length of a token name +const MAX_LENGTH_TOKEN_NAME = 20 + func (req AddTokenRequest) Validate() (ValidationError, bool) { - if len(req.Name) < MIN_LENGTH || len(req.Name) > MAX_LENGTH { - message := fmt.Sprintf("Token name length should be greater than %d characters and less than %d characters", MIN_LENGTH, MAX_LENGTH) + if len(req.Name) < MIN_LENGTH_TOKEN_NAME || len(req.Name) > MAX_LENGTH_TOKEN_NAME { + message := fmt.Sprintf("Token name length should be greater than %d characters and less than %d characters", MIN_LENGTH_TOKEN_NAME, MAX_LENGTH_TOKEN_NAME) return ValidationError{ Field: "Name", Message: message, From 4bc6002b73dd67ab137f31d4f88d9a1cbfd6b490 Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Wed, 2 Mar 2022 13:33:12 +0530 Subject: [PATCH 11/21] log insert error for add token --- go.mod | 11 +++++++++-- go.sum | 13 ++++++++++++- internal/datastore/mongo_store.go | 1 + internal/models/api/token.go | 14 +++++--------- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 72c568a..a0ca5e1 100644 --- a/go.mod +++ b/go.mod @@ -2,14 +2,20 @@ module github.com/SimplQ/simplQ-golang go 1.17 -require go.mongodb.org/mongo-driver v1.8.1 +require ( + github.com/go-chi/chi/v5 v5.0.7 + go.mongodb.org/mongo-driver v1.8.1 +) require ( - github.com/go-chi/chi/v5 v5.0.7 // indirect github.com/go-stack/stack v1.8.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.1 // indirect + github.com/google/go-cmp v0.5.5 // indirect github.com/klauspost/compress v1.13.6 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect + github.com/ttacon/libphonenumber v1.2.1 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.0.2 // indirect github.com/xdg-go/stringprep v1.0.2 // indirect @@ -17,4 +23,5 @@ require ( golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f // indirect golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect golang.org/x/text v0.3.5 // indirect + google.golang.org/protobuf v1.26.0 // indirect ) diff --git a/go.sum b/go.sum index 95a4298..3f0c7d6 100644 --- a/go.sum +++ b/go.sum @@ -5,10 +5,14 @@ github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -24,6 +28,10 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0= +github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w= +github.com/ttacon/libphonenumber v1.2.1 h1:fzOfY5zUADkCkbIafAed11gL1sW+bJ26p6zWLBMElR4= +github.com/ttacon/libphonenumber v1.2.1/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkUl+yR4OAxyEg/M= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= @@ -52,6 +60,9 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/internal/datastore/mongo_store.go b/internal/datastore/mongo_store.go index 8870180..a723954 100644 --- a/internal/datastore/mongo_store.go +++ b/internal/datastore/mongo_store.go @@ -167,6 +167,7 @@ func (mongodb MongoDB) AddTokenToQueue(id db.QueueId, token db.Token) (db.TokenI queueMutex.Unlock() if err != nil { + log.Println(err); return token.Id, err } diff --git a/internal/models/api/token.go b/internal/models/api/token.go index 0058e5f..b11f823 100644 --- a/internal/models/api/token.go +++ b/internal/models/api/token.go @@ -3,9 +3,10 @@ package api import ( "fmt" - "strconv" + "log" "github.com/SimplQ/simplQ-golang/internal/models/db" + "github.com/ttacon/libphonenumber" ) // AddTokenRequest is a model to structure an add token request. @@ -40,14 +41,9 @@ func (req AddTokenRequest) Validate() (ValidationError, bool) { Field: "Name", Message: message, }, false - } else if len(req.ContactNumber) != 10 { - message := fmt.Sprintf("Contact number should be 10 digits") - return ValidationError{ - Field: "ContactNumber", - Message: message, - }, false - } else if _, err := strconv.Atoi(req.ContactNumber); err != nil { - message := fmt.Sprintf("Contact number should only consist of digits") + } else if num, err := libphonenumber.Parse(req.ContactNumber, "IN"); err != nil { + log.Println(num) + message := fmt.Sprint(err) return ValidationError{ Field: "ContactNumber", Message: message, From 8533b6c58e125363bae32e114ade40e9ecf6d0bf Mon Sep 17 00:00:00 2001 From: Lint Action Date: Wed, 2 Mar 2022 08:03:45 +0000 Subject: [PATCH 12/21] Fix code style issues with gofmt --- internal/datastore/mongo_store.go | 2 +- internal/models/api/token.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/datastore/mongo_store.go b/internal/datastore/mongo_store.go index a723954..4cc7f5b 100644 --- a/internal/datastore/mongo_store.go +++ b/internal/datastore/mongo_store.go @@ -167,7 +167,7 @@ func (mongodb MongoDB) AddTokenToQueue(id db.QueueId, token db.Token) (db.TokenI queueMutex.Unlock() if err != nil { - log.Println(err); + log.Println(err) return token.Id, err } diff --git a/internal/models/api/token.go b/internal/models/api/token.go index b11f823..882ea96 100644 --- a/internal/models/api/token.go +++ b/internal/models/api/token.go @@ -41,8 +41,8 @@ func (req AddTokenRequest) Validate() (ValidationError, bool) { Field: "Name", Message: message, }, false - } else if num, err := libphonenumber.Parse(req.ContactNumber, "IN"); err != nil { - log.Println(num) + } else if num, err := libphonenumber.Parse(req.ContactNumber, "IN"); err != nil { + log.Println(num) message := fmt.Sprint(err) return ValidationError{ Field: "ContactNumber", From 5197343688ac7093e4d34f04fd22f8a70bb4c178 Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Sat, 5 Mar 2022 19:01:14 +0530 Subject: [PATCH 13/21] implemented authentication token middleware --- .gitignore | 5 +- cmd/api/main.go | 6 ++ go.mod | 11 +-- go.sum | 23 +++++-- internal/authentication/common.go | 109 ++++++++++++++++++++++++++++++ internal/handler/queue.go | 11 ++- internal/mux/mux.go | 5 ++ 7 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 internal/authentication/common.go diff --git a/.gitignore b/.gitignore index 46f1b76..f64a277 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,7 @@ build/ # vendor/ # temporary build files create by air -tmp/ \ No newline at end of file +tmp/ + +# env file +.env diff --git a/cmd/api/main.go b/cmd/api/main.go index 95f60f4..b8665ab 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -6,9 +6,15 @@ import ( "os" "github.com/SimplQ/simplQ-golang/internal/mux" + + "github.com/joho/godotenv" ) func main() { + // Load environment variables if .env file is present + // ignore if not present + godotenv.Load(); + routes := mux.InitalizeRoutes() listenAddr := ":8080" diff --git a/go.mod b/go.mod index a0ca5e1..c1fc195 100644 --- a/go.mod +++ b/go.mod @@ -7,21 +7,24 @@ require ( go.mongodb.org/mongo-driver v1.8.1 ) +require gopkg.in/square/go-jose.v2 v2.6.0 // indirect + require ( + github.com/auth0/go-jwt-middleware/v2 v2.0.0 github.com/go-stack/stack v1.8.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.1 // indirect - github.com/google/go-cmp v0.5.5 // indirect + github.com/joho/godotenv v1.4.0 github.com/klauspost/compress v1.13.6 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect - github.com/ttacon/libphonenumber v1.2.1 // indirect + github.com/ttacon/libphonenumber v1.2.1 github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.0.2 // indirect github.com/xdg-go/stringprep v1.0.2 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect - golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f // indirect + golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce // indirect golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect - golang.org/x/text v0.3.5 // indirect + golang.org/x/text v0.3.6 // indirect google.golang.org/protobuf v1.26.0 // indirect ) diff --git a/go.sum b/go.sum index 3f0c7d6..b1b3086 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/auth0/go-jwt-middleware/v2 v2.0.0 h1:jft2yYteA6wpwTj1uxSLwE0TlHCjodMQvX7+eyqJiOQ= +github.com/auth0/go-jwt-middleware/v2 v2.0.0/go.mod h1:/y7nPmfWDnJhCbFq22haCAU7vufwsOUzTthLVleE6/8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -11,8 +13,11 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -24,8 +29,9 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0= @@ -43,19 +49,26 @@ github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7Jul go.mongodb.org/mongo-driver v1.8.1 h1:OZE4Wni/SJlrcmSIBRYNzunX5TKxjrTS4jKSnA99oKU= go.mongodb.org/mongo-driver v1.8.1/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f h1:aZp0e2vLN4MToVqnjNEYEtrEA8RH8U8FN1CU7JgqsPU= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI= +golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -65,5 +78,7 @@ google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/l google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/authentication/common.go b/internal/authentication/common.go new file mode 100644 index 0000000..c8891e7 --- /dev/null +++ b/internal/authentication/common.go @@ -0,0 +1,109 @@ +package authentication + +import ( + "context" + "fmt" + "log" + "net/http" + "net/url" + "os" + "strings" + "time" + + "github.com/auth0/go-jwt-middleware/v2/jwks" + "github.com/auth0/go-jwt-middleware/v2/validator" +) + +// Prefix of the authorization header for an anonymous user +const ANONYMOUS_PREFIX = "Anonymous" + +// Prefix of the authorization header for an authenticated user +const BEARER_PREFIX = "Bearer" + +func AuthMiddleware(next http.Handler) http.Handler { + tokenValidator := GetJWTValidator() + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + authorization_header := r.Header.Get("Authorization") + + errorMessage := "Invalid authorization" + + if (strings.HasPrefix(authorization_header, ANONYMOUS_PREFIX)) { + // For anonymous authentication + + // Get the token from the header + uid := strings.Split(authorization_header, ANONYMOUS_PREFIX)[1] + uid = strings.Trim(uid, " \n\r") + + // If a valid token is present + if (len(uid) > 0) { + // Add given token as uid to the context + ctx := context.WithValue(r.Context(), "uid", uid) + next.ServeHTTP(w, r.WithContext(ctx)) + return + } + + errorMessage = "Found no anonymous token" + } else if (strings.HasPrefix(authorization_header, BEARER_PREFIX)) { + // For bearer authentication + + // Get the JWT token from the header + token := strings.Split(authorization_header, BEARER_PREFIX)[1] + token = strings.Trim(token, " \n\r") + + // if a token is present + if (len(token) > 0) { + // Validate the JWT token and get claims + tokenDecoded, err := tokenValidator.ValidateToken(context.TODO(), token) + + if err == nil { + tokenDecoded := tokenDecoded.(*validator.ValidatedClaims) + + // Use the "sub" claim as the uid + uid := tokenDecoded.RegisteredClaims.Subject + + // if a valid uid is present + if (len(uid) > 0) { + // Add the given "sub" as the uid to the context + ctx := context.WithValue(r.Context(), "uid", uid) + next.ServeHTTP(w, r.WithContext(ctx)) + return + } + } else { + log.Println(err) + } + } + errorMessage = "Invalid authentication token" + } + + // If the next handler wasn't called, authentication failed + // return Unauthorized http error + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(fmt.Sprintf(`{"message": "%s"}`, errorMessage))) + }) +} + +// Returns a JWT Token validator +func GetJWTValidator() *validator.Validator { + issuerURL, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/") + if err != nil { + log.Fatalf("Failed to parse the issuer url: %v", err) + } + + provider := jwks.NewCachingProvider(issuerURL, 5*time.Minute) + + jwtValidator, err := validator.New( + provider.KeyFunc, + validator.RS256, + issuerURL.String(), + []string{os.Getenv("AUTH0_AUDIENCE")}, + validator.WithAllowedClockSkew(time.Minute), + ) + + if err != nil { + log.Fatalf("Failed to set up the jwt validator") + } + + return jwtValidator +} diff --git a/internal/handler/queue.go b/internal/handler/queue.go index 1ba9513..b387dda 100644 --- a/internal/handler/queue.go +++ b/internal/handler/queue.go @@ -20,12 +20,17 @@ const queueId key = 0 func GetQueue(w http.ResponseWriter, r *http.Request) { id := r.Context().Value(queueId).(string) - if id == "" { + uid := r.Context().Value("uid").(string) + log.Println(uid) + + if id == "" { http.Error(w, fmt.Sprintf("Invalid Id: %s", id), http.StatusBadRequest) return } - queue, err := datastore.Store.ReadQueue(db.QueueId(id)) - if err != nil { + + queue, err := datastore.Store.ReadQueue(db.QueueId(id)) + + if err != nil { http.Error(w, fmt.Sprint(err), http.StatusInternalServerError) return } diff --git a/internal/mux/mux.go b/internal/mux/mux.go index a1796b4..0aa348f 100644 --- a/internal/mux/mux.go +++ b/internal/mux/mux.go @@ -7,6 +7,7 @@ import ( "github.com/go-chi/chi/v5/middleware" "github.com/SimplQ/simplQ-golang/internal/handler" + "github.com/SimplQ/simplQ-golang/internal/authentication" ) func InitalizeRoutes() chi.Router { @@ -21,6 +22,8 @@ func InitalizeRoutes() chi.Router { // Routes for "queue" resource r.Route("/queue", func(r chi.Router) { + // all routes under queue are required to have authentication + r.Use(authentication.AuthMiddleware) // POST /articles r.Post("/", handler.CreateQueue) @@ -36,6 +39,8 @@ func InitalizeRoutes() chi.Router { // Routes for "token" resource r.Route("/token", func(r chi.Router) { + // all routes under token are required to have authentication + r.Use(authentication.AuthMiddleware) // Add new token to queue r.Post("/", handler.CreateToken) From dbc72e55f1fa7f2fe0d8569c5243100028b5f9c8 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Sat, 5 Mar 2022 13:31:46 +0000 Subject: [PATCH 14/21] Fix code style issues with gofmt --- cmd/api/main.go | 6 +- internal/authentication/common.go | 124 +++++++++++++++--------------- internal/handler/queue.go | 14 ++-- internal/mux/mux.go | 10 +-- 4 files changed, 77 insertions(+), 77 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index b8665ab..bdde16e 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -11,9 +11,9 @@ import ( ) func main() { - // Load environment variables if .env file is present - // ignore if not present - godotenv.Load(); + // Load environment variables if .env file is present + // ignore if not present + godotenv.Load() routes := mux.InitalizeRoutes() diff --git a/internal/authentication/common.go b/internal/authentication/common.go index c8891e7..b9fb567 100644 --- a/internal/authentication/common.go +++ b/internal/authentication/common.go @@ -21,67 +21,67 @@ const ANONYMOUS_PREFIX = "Anonymous" const BEARER_PREFIX = "Bearer" func AuthMiddleware(next http.Handler) http.Handler { - tokenValidator := GetJWTValidator() - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - authorization_header := r.Header.Get("Authorization") - - errorMessage := "Invalid authorization" - - if (strings.HasPrefix(authorization_header, ANONYMOUS_PREFIX)) { - // For anonymous authentication - - // Get the token from the header - uid := strings.Split(authorization_header, ANONYMOUS_PREFIX)[1] - uid = strings.Trim(uid, " \n\r") - - // If a valid token is present - if (len(uid) > 0) { - // Add given token as uid to the context - ctx := context.WithValue(r.Context(), "uid", uid) - next.ServeHTTP(w, r.WithContext(ctx)) - return - } - - errorMessage = "Found no anonymous token" - } else if (strings.HasPrefix(authorization_header, BEARER_PREFIX)) { - // For bearer authentication - - // Get the JWT token from the header - token := strings.Split(authorization_header, BEARER_PREFIX)[1] - token = strings.Trim(token, " \n\r") - - // if a token is present - if (len(token) > 0) { - // Validate the JWT token and get claims - tokenDecoded, err := tokenValidator.ValidateToken(context.TODO(), token) - - if err == nil { - tokenDecoded := tokenDecoded.(*validator.ValidatedClaims) - - // Use the "sub" claim as the uid - uid := tokenDecoded.RegisteredClaims.Subject - - // if a valid uid is present - if (len(uid) > 0) { - // Add the given "sub" as the uid to the context - ctx := context.WithValue(r.Context(), "uid", uid) - next.ServeHTTP(w, r.WithContext(ctx)) - return - } - } else { - log.Println(err) - } - } - errorMessage = "Invalid authentication token" - } - - // If the next handler wasn't called, authentication failed - // return Unauthorized http error - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte(fmt.Sprintf(`{"message": "%s"}`, errorMessage))) - }) + tokenValidator := GetJWTValidator() + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + authorization_header := r.Header.Get("Authorization") + + errorMessage := "Invalid authorization" + + if strings.HasPrefix(authorization_header, ANONYMOUS_PREFIX) { + // For anonymous authentication + + // Get the token from the header + uid := strings.Split(authorization_header, ANONYMOUS_PREFIX)[1] + uid = strings.Trim(uid, " \n\r") + + // If a valid token is present + if len(uid) > 0 { + // Add given token as uid to the context + ctx := context.WithValue(r.Context(), "uid", uid) + next.ServeHTTP(w, r.WithContext(ctx)) + return + } + + errorMessage = "Found no anonymous token" + } else if strings.HasPrefix(authorization_header, BEARER_PREFIX) { + // For bearer authentication + + // Get the JWT token from the header + token := strings.Split(authorization_header, BEARER_PREFIX)[1] + token = strings.Trim(token, " \n\r") + + // if a token is present + if len(token) > 0 { + // Validate the JWT token and get claims + tokenDecoded, err := tokenValidator.ValidateToken(context.TODO(), token) + + if err == nil { + tokenDecoded := tokenDecoded.(*validator.ValidatedClaims) + + // Use the "sub" claim as the uid + uid := tokenDecoded.RegisteredClaims.Subject + + // if a valid uid is present + if len(uid) > 0 { + // Add the given "sub" as the uid to the context + ctx := context.WithValue(r.Context(), "uid", uid) + next.ServeHTTP(w, r.WithContext(ctx)) + return + } + } else { + log.Println(err) + } + } + errorMessage = "Invalid authentication token" + } + + // If the next handler wasn't called, authentication failed + // return Unauthorized http error + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(fmt.Sprintf(`{"message": "%s"}`, errorMessage))) + }) } // Returns a JWT Token validator @@ -105,5 +105,5 @@ func GetJWTValidator() *validator.Validator { log.Fatalf("Failed to set up the jwt validator") } - return jwtValidator + return jwtValidator } diff --git a/internal/handler/queue.go b/internal/handler/queue.go index b387dda..8de42d2 100644 --- a/internal/handler/queue.go +++ b/internal/handler/queue.go @@ -21,16 +21,16 @@ const queueId key = 0 func GetQueue(w http.ResponseWriter, r *http.Request) { id := r.Context().Value(queueId).(string) uid := r.Context().Value("uid").(string) - log.Println(uid) - - if id == "" { + log.Println(uid) + + if id == "" { http.Error(w, fmt.Sprintf("Invalid Id: %s", id), http.StatusBadRequest) return } - - queue, err := datastore.Store.ReadQueue(db.QueueId(id)) - - if err != nil { + + queue, err := datastore.Store.ReadQueue(db.QueueId(id)) + + if err != nil { http.Error(w, fmt.Sprint(err), http.StatusInternalServerError) return } diff --git a/internal/mux/mux.go b/internal/mux/mux.go index 0aa348f..da657a8 100644 --- a/internal/mux/mux.go +++ b/internal/mux/mux.go @@ -6,8 +6,8 @@ import ( "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" - "github.com/SimplQ/simplQ-golang/internal/handler" "github.com/SimplQ/simplQ-golang/internal/authentication" + "github.com/SimplQ/simplQ-golang/internal/handler" ) func InitalizeRoutes() chi.Router { @@ -22,8 +22,8 @@ func InitalizeRoutes() chi.Router { // Routes for "queue" resource r.Route("/queue", func(r chi.Router) { - // all routes under queue are required to have authentication - r.Use(authentication.AuthMiddleware) + // all routes under queue are required to have authentication + r.Use(authentication.AuthMiddleware) // POST /articles r.Post("/", handler.CreateQueue) @@ -39,8 +39,8 @@ func InitalizeRoutes() chi.Router { // Routes for "token" resource r.Route("/token", func(r chi.Router) { - // all routes under token are required to have authentication - r.Use(authentication.AuthMiddleware) + // all routes under token are required to have authentication + r.Use(authentication.AuthMiddleware) // Add new token to queue r.Post("/", handler.CreateToken) From beeae61daee62aeac9444fe117601bfc32c95eaf Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Fri, 11 Mar 2022 18:15:03 +0530 Subject: [PATCH 15/21] explaning comments --- internal/authentication/common.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/authentication/common.go b/internal/authentication/common.go index b9fb567..1190b39 100644 --- a/internal/authentication/common.go +++ b/internal/authentication/common.go @@ -20,12 +20,18 @@ const ANONYMOUS_PREFIX = "Anonymous" // Prefix of the authorization header for an authenticated user const BEARER_PREFIX = "Bearer" +// Authentication Middleware +// Calls the next handler with `uid` in the `context` which can be used as a unique +// id for any user. +// Returns `http.StatusUnauthorized` to the client if the authorization token is not +// found or is invalid. func AuthMiddleware(next http.Handler) http.Handler { tokenValidator := GetJWTValidator() return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { authorization_header := r.Header.Get("Authorization") + // Default error message errorMessage := "Invalid authorization" if strings.HasPrefix(authorization_header, ANONYMOUS_PREFIX) { @@ -43,7 +49,7 @@ func AuthMiddleware(next http.Handler) http.Handler { return } - errorMessage = "Found no anonymous token" + errorMessage = "Anonymous token not found" } else if strings.HasPrefix(authorization_header, BEARER_PREFIX) { // For bearer authentication From 6b9bfb4014def6d5594fc527bd3ac4dea193f6a8 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Fri, 11 Mar 2022 12:45:29 +0000 Subject: [PATCH 16/21] Fix code style issues with gofmt --- internal/authentication/common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/authentication/common.go b/internal/authentication/common.go index 1190b39..cb16dab 100644 --- a/internal/authentication/common.go +++ b/internal/authentication/common.go @@ -31,7 +31,7 @@ func AuthMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { authorization_header := r.Header.Get("Authorization") - // Default error message + // Default error message errorMessage := "Invalid authorization" if strings.HasPrefix(authorization_header, ANONYMOUS_PREFIX) { From de112cf2068e7786c894ab03dd34065455882558 Mon Sep 17 00:00:00 2001 From: Anish Sharma Date: Sat, 12 Mar 2022 11:37:25 +0530 Subject: [PATCH 17/21] Update authorization with main (#20) * Made gh action trigger on PRs also to get around stuck status checks (#19) * Made gh action trigger on PRs also to get around stuck status checks * Modified to trigger only on PRs * Renamed check * Add Token to Queue (#18) * implemented add token for queue store * implemented create token route * Fix code style issues with gofmt * read tokens in the queue in readqueue * Fix code style issues with gofmt * implemented token number * Fix code style issues with gofmt * added read token route * Fix code style issues with gofmt * separated name length constants * log insert error for add token * Fix code style issues with gofmt * refactoring mongo store * Fix code style issues with gofmt Co-authored-by: Lint Action Co-authored-by: Nithin Co-authored-by: Lint Action --- .github/workflows/vet_and_format.yml | 4 ++-- internal/datastore/mongo_store.go | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/vet_and_format.yml b/.github/workflows/vet_and_format.yml index f3ea9de..606b7f4 100644 --- a/.github/workflows/vet_and_format.yml +++ b/.github/workflows/vet_and_format.yml @@ -1,6 +1,6 @@ -name: Post-push-checks +name: PR-checks -on: [push] +on: [pull_request] jobs: build-check: diff --git a/internal/datastore/mongo_store.go b/internal/datastore/mongo_store.go index 4cc7f5b..74d573c 100644 --- a/internal/datastore/mongo_store.go +++ b/internal/datastore/mongo_store.go @@ -150,13 +150,14 @@ func (mongodb MongoDB) AddTokenToQueue(id db.QueueId, token db.Token) (db.TokenI // Lock queue to ensure 2 concurrent add tokens don't happen queueMutex.Lock() + // Unlock the mutex before returning + defer queueMutex.Unlock() // if there were 2 concurrent calls to this function, 2 tokens might get the same number max, err := mongodb.GetMaxToken(id) if err != nil { log.Fatal(err) - queueMutex.Unlock() return token.Id, err } @@ -164,8 +165,6 @@ func (mongodb MongoDB) AddTokenToQueue(id db.QueueId, token db.Token) (db.TokenI result, err := mongodb.Token.InsertOne(context.TODO(), token) - queueMutex.Unlock() - if err != nil { log.Println(err) return token.Id, err @@ -177,17 +176,19 @@ func (mongodb MongoDB) AddTokenToQueue(id db.QueueId, token db.Token) (db.TokenI } func (mongodb MongoDB) GetMaxToken(id db.QueueId) (uint32, error) { + // select all tokens that belong to this queue filter := bson.D{ // queueid is a string this time {Key: "queueid", Value: id}, } - sort := bson.D{ + // sort tokens by descending order of token number + sortFilter := bson.D{ {Key: "tokennumber", Value: -1}, } findOptions := options.Find() - findOptions.SetSort(sort) + findOptions.SetSort(sortFilter) findOptions.SetLimit(1) cursor, err := mongodb.Token.Find(context.TODO(), filter, findOptions) @@ -207,6 +208,8 @@ func (mongodb MongoDB) GetMaxToken(id db.QueueId) (uint32, error) { return 0, nil } + // return the token number of the first token + // first token is highest as the list is in descending order return tokens[0].TokenNumber, nil } From 8db5c182cc9464339d0cef24a09d95fdfa3d5a50 Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Sat, 19 Mar 2022 14:53:18 +0530 Subject: [PATCH 18/21] use 'uid' as a constant --- internal/authentication/common.go | 7 +++++-- internal/handler/queue.go | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/authentication/common.go b/internal/authentication/common.go index cb16dab..aefed19 100644 --- a/internal/authentication/common.go +++ b/internal/authentication/common.go @@ -20,6 +20,9 @@ const ANONYMOUS_PREFIX = "Anonymous" // Prefix of the authorization header for an authenticated user const BEARER_PREFIX = "Bearer" +// Key for the "uid" stored in context +const UID = "uid" + // Authentication Middleware // Calls the next handler with `uid` in the `context` which can be used as a unique // id for any user. @@ -44,7 +47,7 @@ func AuthMiddleware(next http.Handler) http.Handler { // If a valid token is present if len(uid) > 0 { // Add given token as uid to the context - ctx := context.WithValue(r.Context(), "uid", uid) + ctx := context.WithValue(r.Context(), UID, uid) next.ServeHTTP(w, r.WithContext(ctx)) return } @@ -71,7 +74,7 @@ func AuthMiddleware(next http.Handler) http.Handler { // if a valid uid is present if len(uid) > 0 { // Add the given "sub" as the uid to the context - ctx := context.WithValue(r.Context(), "uid", uid) + ctx := context.WithValue(r.Context(), UID, uid) next.ServeHTTP(w, r.WithContext(ctx)) return } diff --git a/internal/handler/queue.go b/internal/handler/queue.go index 8de42d2..eac433d 100644 --- a/internal/handler/queue.go +++ b/internal/handler/queue.go @@ -8,6 +8,7 @@ import ( "net/http" "time" + "github.com/SimplQ/simplQ-golang/internal/authentication" "github.com/SimplQ/simplQ-golang/internal/datastore" "github.com/SimplQ/simplQ-golang/internal/models/api" "github.com/SimplQ/simplQ-golang/internal/models/db" @@ -20,7 +21,7 @@ const queueId key = 0 func GetQueue(w http.ResponseWriter, r *http.Request) { id := r.Context().Value(queueId).(string) - uid := r.Context().Value("uid").(string) + uid := r.Context().Value(authentication.UID).(string) log.Println(uid) if id == "" { From 5f24ab80b47ce9ebafb6e545837915bb042e09d2 Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Sat, 19 Mar 2022 15:02:56 +0530 Subject: [PATCH 19/21] renamed common.go to middleware.go for authentication package --- internal/authentication/{common.go => middleware.go} | 0 internal/handler/queue.go | 1 + 2 files changed, 1 insertion(+) rename internal/authentication/{common.go => middleware.go} (100%) diff --git a/internal/authentication/common.go b/internal/authentication/middleware.go similarity index 100% rename from internal/authentication/common.go rename to internal/authentication/middleware.go diff --git a/internal/handler/queue.go b/internal/handler/queue.go index eac433d..72f03a7 100644 --- a/internal/handler/queue.go +++ b/internal/handler/queue.go @@ -22,6 +22,7 @@ const queueId key = 0 func GetQueue(w http.ResponseWriter, r *http.Request) { id := r.Context().Value(queueId).(string) uid := r.Context().Value(authentication.UID).(string) + // TODO: Remove print statement once uid is made use of log.Println(uid) if id == "" { From f6345bfcd6ff93e4cc8aec1a634a110bd3d39ca6 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Sat, 19 Mar 2022 09:34:09 +0000 Subject: [PATCH 20/21] Fix code style issues with gofmt --- internal/handler/queue.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handler/queue.go b/internal/handler/queue.go index 72f03a7..975558a 100644 --- a/internal/handler/queue.go +++ b/internal/handler/queue.go @@ -22,7 +22,7 @@ const queueId key = 0 func GetQueue(w http.ResponseWriter, r *http.Request) { id := r.Context().Value(queueId).(string) uid := r.Context().Value(authentication.UID).(string) - // TODO: Remove print statement once uid is made use of + // TODO: Remove print statement once uid is made use of log.Println(uid) if id == "" { From 4cd77916523816e447b0cc7c34cbb3398c2bb58c Mon Sep 17 00:00:00 2001 From: aneeshsharma Date: Sat, 19 Mar 2022 15:04:53 +0530 Subject: [PATCH 21/21] made getJWTValidator private --- internal/authentication/middleware.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/authentication/middleware.go b/internal/authentication/middleware.go index aefed19..aa3a935 100644 --- a/internal/authentication/middleware.go +++ b/internal/authentication/middleware.go @@ -29,7 +29,7 @@ const UID = "uid" // Returns `http.StatusUnauthorized` to the client if the authorization token is not // found or is invalid. func AuthMiddleware(next http.Handler) http.Handler { - tokenValidator := GetJWTValidator() + tokenValidator := getJWTValidator() return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { authorization_header := r.Header.Get("Authorization") @@ -94,7 +94,7 @@ func AuthMiddleware(next http.Handler) http.Handler { } // Returns a JWT Token validator -func GetJWTValidator() *validator.Validator { +func getJWTValidator() *validator.Validator { issuerURL, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/") if err != nil { log.Fatalf("Failed to parse the issuer url: %v", err)