From 63bd090a201d55ed7469861466009e654764174e Mon Sep 17 00:00:00 2001 From: Harshit Raj Date: Sun, 25 Jul 2021 02:40:09 +0530 Subject: [PATCH] release 1.2 Some minor bug fix, updated readme and forgot-password addded --- .github/workflows/go.yml | 5 +- .gitignore | 3 +- README.md | 150 +++++++++++++++++++++++++++++---------- config/config.go | 2 +- config/validate.go | 22 ++++-- db/db.go | 2 +- db/otp.go | 18 +++++ db/redeem.go | 58 +++++++-------- db/user.go | 12 +++- main.go | 4 ++ routes/redeem.go | 11 ++- routes/trnxn.go | 21 +++++- routes/user.go | 138 ++++++++++++++++++++++++++++++++++- 13 files changed, 356 insertions(+), 90 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index b56312c..8cb27f1 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -19,7 +19,4 @@ jobs: go-version: 1.16 - name: Build - run: go build -v ./... - - - name: Test - run: go test -v ./... + run: go build -v ./... \ No newline at end of file diff --git a/.gitignore b/.gitignore index 96adf93..031090b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ config/email_cred.go iitk-coin data.db -commands* temp* -.* +.* \ No newline at end of file diff --git a/README.md b/README.md index a92b4ee..c4fe215 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # iitk-coin -**Summer Project 2021** ---- -**SnT Project 2021, Programming Club** ---- + +## **Summer Project 2021** + +## **SnT Project 2021, Programming Club** This repository contains the backend code for the IITK Coin which is a reward based psuedo currency of IIT Kanpur. @@ -12,6 +12,7 @@ This repository contains the backend code for the IITK Coin which is a reward ba - [Midterm Documentation](https://docs.google.com/document/d/1bvOWH4k0U-l2pQ1jLWIDzOkJ2wbHNW4jJw7tMWkUV6o/edit?usp=sharing) ## Table Of Content + - [Development Environment](#development-environment) - [Directory Structure](#directory-structure) - [Usage](#usage) @@ -22,15 +23,18 @@ This repository contains the backend code for the IITK Coin which is a reward ba ## Development Environment ```bash -- go version: go1.16.6 linux/amd64 # https://golang.org/dl/ -- text editor: VSCode # https://code.visualstudio.com/download -- terminal: Zsh # https://ohmyz.sh/ +- OS: Ubuntu 20.04.2 LTS x86-64 # https://ubuntu.com/download +- Kernel: Linux 5.8.0-59-generic # https://kernel.ubuntu.com/ +- go version: go1.16.6 linux/amd64 # https://golang.org/dl/ +- text editor: VSCode # https://code.visualstudio.com/download +- terminal: Zsh # https://ohmyz.sh/ ``` ## Directory Structure + ``` . -~/go/src/github.com/1-Harshit/iitk-coin +~go/src/github.com/1-Harshit/iitk-coin ├── auth │   └── auth.go ├── config @@ -39,6 +43,7 @@ This repository contains the backend code for the IITK Coin which is a reward ba │   ├── otp.go │   ├── settings.go │   └── validate.go +├── data.db ├── db │   ├── db.go │   ├── otp.go @@ -47,6 +52,7 @@ This repository contains the backend code for the IITK Coin which is a reward ba ├── Dockerfile ├── go.mod ├── go.sum +├── iitk-coin ├── LICENSE ├── main.go ├── Models.png @@ -57,34 +63,39 @@ This repository contains the backend code for the IITK Coin which is a reward ba ├── user.go └── utility.go -4 directories, 21 files +4 directories, 23 files ``` ## Usage + ### Use this Repo + ```bash mkdir $GOPATH/src/github.com/1-Harshit cd $GOPATH/src/github.com/1-Harshit git clone https://github.com/1-Harshit/iitk-coin.git cd iitk-coin -``` -```bash -go run main.go + +go run main.go # or build the program and run the executable go build ./iitk-coin ``` + ### Use Docker Image + ```bash docker run --rm -p 8080:8080 1harshit/iitk-coin ``` -Output should look like + +Expected Output: ``` 2021/07/18 01:03:46 Starting server. Listening on http://localhost:8080 ``` ## Endpoints + POST requests take place via `JSON` requests. A typical usage would look like ```bash @@ -92,98 +103,159 @@ curl -H "Content-Type: application/json" [-H "Authorization: Bearer JWT"] --requ # or if using get curl [-H "Authorization: Bearer JWT"] --request GET http://localhost:8080/ ``` + #### Signup + - `/signup/otp` : `POST` + ```json -{"name":"", "roll":"", "email":""} +{ "name": "", "roll": "", "email": "" } ``` - `/signup` : `POST` + ```json -{"name":"", "roll":"", "email":"", "password":"", "otp":"", "batch":""} +{ + "name": "", + "roll": "", + "email": "", + "password": "", + "otp": "", + "batch": "" +} ``` + #### Login + - `/login` : `POST` + ```json -{"roll":"", "password":""} +{ "roll": "", "password": "" } ``` - `/secretpage` : `GET` + ```bash curl -H "Authorization: Bearer $JWT" --request GET http://localhost:8080/secretpage ``` Auth Header needed in all endpoints below this + #### User's Info + - `/user/info` : `GET` + ```bash curl -H "Authorization: Bearer $JWT" --request GET http://localhost:8080/user/info ``` + - `/user/reward` : `GET` + ```bash curl -H "Authorization: Bearer $JWT" --request GET http://localhost:8080/user/reward ``` + - `/user/transaction` : `GET` + ```bash curl -H "Authorization: Bearer $JWT" --request GET http://localhost:8080/user/transaction ``` + - `/user/redeem` : `GET` + ```bash curl -H "Authorization: Bearer $JWT" --request GET http://localhost:8080/user/redeem ``` + +#### Reset Password + +- `/forgotpass/otp` : `POST` + +```json +{ "roll": "", "email": "" } +``` + +- `/forgotpass` : `POST` + +```json +{ "roll": "", "password": "", "otp": "" } +``` + #### Rewards + - `/reward` : `POST` Only GenSec and AH + ```json -{"roll":"", "coins":""} +{ "roll": "", "coins": "" } ``` #### Transfer + - `/transfer/otp` : `GET` + ```bash curl -H "Authorization: Bearer $JWT" --request GET http://localhost:8080/transfer/otp ``` -- `/transfer` : `POST` + +- `/transfer` : `POST` + ```json -{"roll":"", "coins":"", "otp":""} +{ "roll": "", "coins": "", "otp": "" } ``` #### Store + - `/store/list` : `GET` + ```bash curl --request GET http://localhost:8080/store/list ``` + - `/store/add` : `POST` Only GenSec and AH + ```json -{"name":"", "value":""} +{ "name": "", "value": "" } ``` + - `/store/remove` : `POST` Only GenSec and AH + ```json -{"itemNo":""} +{ "itemNo": "" } ``` #### Redeem + - `/redeem/request/otp` : `GET` + ```bash curl -H "Authorization: Bearer $JWT" --request GET http://localhost:8080/redeem/request/otp ``` + - `/redeem/request` : `POST` + ```json -{"itemNo":"", "otp":""} +{ "itemNo": "", "otp": "" } ``` + - `/redeem/list` : `GET` Only GenSec and AH + ```bash curl -H "Authorization: Bearer $JWT" --request GET http://localhost:8080//redeem/list ``` + - `/redeem/approve` : `POST` Only GenSec and AH + ```json -{"redeemid":""} +{ "redeemid": "" } ``` + - `/redeem/reject` : `POST` Only GenSec and AH + ```json -{"redeemid":""} +{ "redeemid": "" } ``` -### How to use +### How to use 1. Run the `main.go` file this will Listen and Serve on `localhost:8080` 2. Use `curl` to use endpoints as shown above @@ -192,20 +264,20 @@ curl -H "Authorization: Bearer $JWT" --request GET http://localhost:8080//redeem ![Models](Models.png "Database Struct") - ## Settings + ### about `config/settings.go` - Some unkown variables are stored there. - - - Path of DB - - Max coins one can have - - Minimum Events needed for transfer - - tax - - const IntraBatchTax float64 = 0.02 - - const InterBatchTax float64 = 0.33 - - const IsStoreOpen bool = true - - -Footnotes ---- + +Some unkown variables are stored there. + +- Path of DB +- Max coins one can have +- Minimum Events needed for transfer +- tax + - const IntraBatchTax float64 = 0.02 + - const InterBatchTax float64 = 0.33 +- const IsStoreOpen bool = true + +## Footnotes + I'd like to name it **Koins** diff --git a/config/config.go b/config/config.go index a4fe633..6b36b1d 100644 --- a/config/config.go +++ b/config/config.go @@ -74,7 +74,7 @@ type Redeem struct { type Reward struct { Time string `json:"time"` - Coins int `json:"coins"` + Coins float64 `json:"coins"` Remarks string `json:"remarks"` } diff --git a/config/validate.go b/config/validate.go index 6c8c367..ea65f38 100644 --- a/config/validate.go +++ b/config/validate.go @@ -9,9 +9,9 @@ func ValidateUserforOTP(t User) string { if t.Roll <= 0 { return "Roll Number not found in request" } - if t.Name == "" { - return "Name not found in request" - } + // if t.Name == "" { + // return "Name not found in request" + // } if t.Email == "" { return "Email not found in request" } @@ -48,6 +48,20 @@ func ValidateUser(t User) string { return "" } +// Check non empty request and email +func ValidatePass(t User) string { + if t.Roll <= 0 { + return "Roll Number not found in request" + } + if t.Password == "" { + return "Password not found in request" + } + if t.OTP == "" { + return "OTP not found in the request" + } + return "" +} + func ValidateCredentials(t User) string { if t.Roll == 0 { return "Roll Number not found in request" @@ -65,7 +79,7 @@ func ValidateReward(t Wallet) string{ if t.Coins < 0 { return "Positive coins needed in request" } - if x := 100*t.Coins; x == float64(int(x)){ + if x := 100*t.Coins; x != float64(int(x)){ return "Coins only allowed till two decimal places" } return "" diff --git a/db/db.go b/db/db.go index 15ffa74..fb997ae 100644 --- a/db/db.go +++ b/db/db.go @@ -309,7 +309,7 @@ func TransferCoins(t c.Wallet, f *c.Claims) error { return errors.New("max limit of coins for user exeeded") } - txn_stm := `INSERT INTO "main"."Transaction" + txn_stm := `INSERT INTO "main"."Transactions" ("from", "to", "sent", "tax", "remarks") VALUES (?, ?, ?, ?, ?);` diff --git a/db/otp.go b/db/otp.go index f2aef1c..c424281 100644 --- a/db/otp.go +++ b/db/otp.go @@ -72,6 +72,24 @@ func ExceedMaxOTP(roll int) bool { return count > 2 } +// count no of otp +func ExceedMaxOTP_forgotpass(roll int) bool { + timestr := time.Now().Add(-7 * 24 * time.Hour).Unix() + command := `SELECT COUNT(*) FROM "main"."OTPInfo" WHERE "roll" = ? AND isUsed=0 AND time > ?;` + + statement, err := Mydb.Prepare(command) + if err != nil { + return false + } + defer statement.Close() + var count int + err = statement.QueryRow(roll, timestr).Scan(&count) + if err != nil { + return false + } + return count > 2 +} + // Mark otp as used func MarkOTP(sl int) error { // Update OTP ID in database diff --git a/db/redeem.go b/db/redeem.go index 1712b5f..9432153 100644 --- a/db/redeem.go +++ b/db/redeem.go @@ -20,7 +20,7 @@ func GetItem(t int) (c.Item, error) { func GetItems() ([]c.Item, error) { // query - row, err := Mydb.Query(`SELECT "itemNo", "name", "value" FROM "main"."Store" WHERE status=1 ORDER BY value`) + row, err := Mydb.Query(`SELECT "itemNo", "name", "value" FROM "main"."Store" WHERE isavailable=1 ORDER BY value`) if err != nil { return nil, err } @@ -37,16 +37,16 @@ func GetItems() ([]c.Item, error) { AllItems = append(AllItems, entry) } if err := row.Err(); err != nil { - return nil, err - } + return nil, err + } return AllItems, nil } // Insert into db func DeleteItems(t c.Item) error { - + // Insert in Store - insert_item := `UPDATE "main"."Store" SET "status"=0 WHERE "itemNo"=?;` + insert_item := `UPDATE "main"."Store" SET "isavailable"=0 WHERE "itemNo"=?;` statement, err := Mydb.Prepare(insert_item) if err != nil { @@ -54,12 +54,12 @@ func DeleteItems(t c.Item) error { } _, err = statement.Exec(t.ItemNo) - + return err } func InsertItems(t c.Item) error { - + // Insert in Store insert_item := `INSERT INTO "main"."Store" ("name", "value") VALUES (?, ?) @@ -71,13 +71,13 @@ func InsertItems(t c.Item) error { } _, err = statement.Exec(t.Name, t.Value) - + return err } func ReqRedeem(t c.Redeem) error { row, err := Mydb.Query(` - SELECT Redeem.sl, Redeem.itemNo, Store.value + SELECT Redeem.redeemID, Redeem.itemNo, Store.value FROM "main"."Redeem" INNER JOIN "main"."Store" ON Redeem.itemNo=Store.itemNo WHERE Redeem.status=0 AND Redeem.roll = ? @@ -99,8 +99,8 @@ func ReqRedeem(t c.Redeem) error { total += entry.Value } if err := row.Err(); err != nil { - return err - } + return err + } itm, _ := GetItem(t.ItemNo) coins, _ := GetCoins(t.Roll) if int(coins) < total+itm.Value { @@ -108,7 +108,7 @@ func ReqRedeem(t c.Redeem) error { } // Insert in Store - stm := `INSERT INTO "main"."Redeem" ("roll", itemNo") + stm := `INSERT INTO "main"."Redeem" ("roll", "itemNo") VALUES (?, ?) ;` @@ -118,14 +118,14 @@ func ReqRedeem(t c.Redeem) error { } _, err = statement.Exec(t.Roll, t.ItemNo) - + return err } func GetReedem() ([]c.Redeem, error) { // query row, err := Mydb.Query(` - SELECT Redeem.sl, Redeem.time, Redeem.roll, Redeem.itemNo, Store.name, Store.value + SELECT Redeem.redeemID, Redeem.time, Redeem.roll, Redeem.itemNo, Store.name, Store.value FROM "main"."Redeem" INNER JOIN "main"."Store" ON Redeem.itemNo=Store.itemNo WHERE Redeem.status=0 @@ -147,30 +147,30 @@ func GetReedem() ([]c.Redeem, error) { AllItems = append(AllItems, entry) } if err := row.Err(); err != nil { - return nil, err - } + return nil, err + } return AllItems, nil } func RejectRedeem(t int) error { - - statement, err := Mydb.Prepare(`UPDATE "main"."Redeem" SET "status"=-1 WHERE "sl"=?;`) + + statement, err := Mydb.Prepare(`UPDATE "main"."Redeem" SET "status"=-1 WHERE "redeemID"=?;`) if err != nil { return err } _, err = statement.Exec(t) - + return err } func ApproveRedeem(t int) error { - + row := Mydb.QueryRow(` - SELECT Redeem.sl, Redeem.time, Redeem.roll, Redeem.itemNo, Store.name, Store.value + SELECT Redeem.redeemID, Redeem.time, Redeem.roll, Redeem.itemNo, Store.name, Store.value FROM "main"."Redeem" INNER JOIN "main"."Store" ON Redeem.itemNo=Store.itemNo - WHERE Redeem.status=0 AND Redeem.sl = ? + WHERE Redeem.status=0 AND Redeem.redeemID = ? ;`, t) redm := c.Redeem{} err := row.Scan(&redm.Id, &redm.Time, &redm.Roll, &redm.ItemNo, &redm.Name, &redm.Value) @@ -209,23 +209,19 @@ func ApproveRedeem(t int) error { return errors.New("sender wallet doesn't enough capacity") } - - txn_stm := `INSERT INTO "main"."Transaction" - ("from", "to", "sent", "tax", "remarks") - VALUES (?, ?, ?, ?, ?);` - - statement2, err := tx.Prepare(txn_stm) + // update reedeem status + stm := `UPDATE "main"."Redeem" SET "status"=1 WHERE "redeemID"=?;` + statement, err = tx.Prepare(stm) if err != nil { tx.Rollback() return err } - defer statement2.Close() - _, err = statement2.Exec(redm.Roll, 200433, redm.Value, redm.Value, "Reedeem amount") + _, err = statement.Exec(redm.Id) if err != nil { tx.Rollback() return err } err = tx.Commit() return err -} \ No newline at end of file +} diff --git a/db/user.go b/db/user.go index 1ac46c5..6535cf0 100644 --- a/db/user.go +++ b/db/user.go @@ -57,7 +57,7 @@ func GetCoins(roll int) (float64, error) { // Get from Rewards func GetUserRewards(roll int) ([]c.Reward, error) { - command := `SELECT "time", "coins", "remarks" FROM "main"."Rewards" WHERE "roll" = $1 AND status = 1;` + command := `SELECT "time", "coins", "remarks" FROM "main"."Reward" WHERE "roll" = $1 AND status = 1;` statement, err := Mydb.Prepare(command) if err != nil { return nil, err @@ -82,7 +82,7 @@ func GetUserRewards(roll int) ([]c.Reward, error) { // Get from Transactions func GetUserTransaction(roll int) ([]c.Tnxn, error) { - command := `SELECT "time", "from", "to", "sent", "tax", "remarks" FROM "main"."Transactions" WHERE "to" = $1 OR from = $1;` + command := `SELECT "time", "from", "to", "sent", "tax", "remarks" FROM "main"."Transactions" WHERE "to" = $1 OR "from" = $1;` statement, err := Mydb.Prepare(command) if err != nil { return nil, err @@ -107,7 +107,7 @@ func GetUserTransaction(roll int) ([]c.Tnxn, error) { func GetUserRedeem(roll int) ([]c.Redeem, error) { command := ` - SELECT Redeem.sl, Redeem.time, Redeem.roll, Redeem.status, Redeem.itemNo, Store.name, Store.value + SELECT Redeem.redeemID, Redeem.time, Redeem.roll, Redeem.status, Redeem.itemNo, Store.name, Store.value FROM "main"."Redeem" INNER JOIN "main"."Store" ON Redeem.itemNo=Store.itemNo WHERE Redeem.roll = $1 @@ -135,3 +135,9 @@ func GetUserRedeem(roll int) ([]c.Redeem, error) { return redeem, nil } + +// Change password +func ChangePassword(t c.User) error { + _, err := Mydb.Exec(`UPDATE "main"."User" SET password = $1 WHERE roll = $2;`, t.Password, t.Roll) + return err +} \ No newline at end of file diff --git a/main.go b/main.go index d14e4c4..99d25b1 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,10 @@ func main() { mux.HandleFunc("/login", r.Login) mux.HandleFunc("/secretpage", r.SecretPage) + // forgotpass + mux.HandleFunc("/forgotpass/otp", r.ForgotPassOTP) + mux.HandleFunc("/forgotpass", r.ForgotPass) + // Reward AH Gensec mux.HandleFunc("/reward", r.Reward) diff --git a/routes/redeem.go b/routes/redeem.go index 9e4b162..d5a173b 100644 --- a/routes/redeem.go +++ b/routes/redeem.go @@ -23,6 +23,7 @@ func ListItems(rw http.ResponseWriter, _ *http.Request) { } rw.WriteHeader(http.StatusBadRequest) json.NewEncoder(rw).Encode(response) + return } response := c.RespData{ Message: "All active items are listed", @@ -73,6 +74,7 @@ func AddItems(rw http.ResponseWriter, req *http.Request) { if valid := c.ValidateItem(t); valid != "" { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp(valid, "Bad Request")) + return } // add to db @@ -126,6 +128,7 @@ func RemoveItems(rw http.ResponseWriter, req *http.Request) { if t.ItemNo == 0 { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp("Item No not found in request", "Bad Request")) + return } // add to db @@ -167,6 +170,7 @@ func OTPforRedeem(rw http.ResponseWriter, req *http.Request) { if db.ExceedMaxOTP(t.Roll) { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp("too frequent otp requests", "please try again after 5 minutes")) + return } // Get OTP @@ -186,6 +190,7 @@ func OTPforRedeem(rw http.ResponseWriter, req *http.Request) { if valid := c.Email(t, OTP, 3); valid != "" { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp(valid, "Error in sending Email")) + return } @@ -223,6 +228,7 @@ func RedeemRequest(rw http.ResponseWriter, req *http.Request) { if t.ItemNo == 0 { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp("ItemNo not found in request", "Bad Request")) + return } t.Roll = usr.Roll @@ -250,7 +256,7 @@ func RedeemRequest(rw http.ResponseWriter, req *http.Request) { if err != nil { rw.WriteHeader(http.StatusBadRequest) - rw.Write(Rsp(err.Error(), "Couldnot Transfer coins")) + rw.Write(Rsp(err.Error(), "Couldnot redeem coins")) return } @@ -286,6 +292,7 @@ func ListRedeemRequest(rw http.ResponseWriter, req *http.Request) { } rw.WriteHeader(http.StatusBadRequest) json.NewEncoder(rw).Encode(response) + return } response := c.RespData{ Message: "All pending requests are listed", @@ -332,6 +339,7 @@ func RejectRedeemRequest(rw http.ResponseWriter, req *http.Request) { if t.Id == 0 { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp("ID not found in request", "Bad Request")) + return } // Alter DB @@ -385,6 +393,7 @@ func ApproveRedeemRequest(rw http.ResponseWriter, req *http.Request) { if t.Id == 0 { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp("ID not found in request", "Bad Request")) + return } // Alter DB diff --git a/routes/trnxn.go b/routes/trnxn.go index 93ef840..e8e3e80 100644 --- a/routes/trnxn.go +++ b/routes/trnxn.go @@ -49,6 +49,20 @@ func Reward(rw http.ResponseWriter, req *http.Request) { return } + // get user + user, err := db.GetUser(t.Roll) + if err != nil { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp(err.Error(), "Error in fetching user")) + return + } + // check if user is Gensec or AH + if user.UsrType == 1 { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp("GenSec AH Cannot get coins", "")) + return + } + // add to db err = db.RewardCoins(t) if err != nil { @@ -82,12 +96,12 @@ func OTPforTransfer(rw http.ResponseWriter, req *http.Request) { rw.Write(Rsp(err.Error(), "Server Error")) return } - // Check Spam if db.ExceedMaxOTP(t.Roll) { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp("too frequent otp requests", "please try again after 5 minutes")) + return } // Get OTP @@ -107,9 +121,9 @@ func OTPforTransfer(rw http.ResponseWriter, req *http.Request) { if valid := c.Email(t, OTP, 2); valid != "" { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp(valid, "Error in sending Email")) + return } - // Everything went well rw.WriteHeader(http.StatusOK) rw.Write(Rsp("", "email Sent")) @@ -144,10 +158,11 @@ func Transfer(rw http.ResponseWriter, req *http.Request) { if valid := ValidateTransfer(&t); valid != "" { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp(valid, "Bad Request")) + return } // check otp - hashotp, otpID, err := db.GetOTP(t.Roll) + hashotp, otpID, err := db.GetOTP(f.Roll) if err != nil { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp(err.Error(), "Error in fetching OTP")) diff --git a/routes/user.go b/routes/user.go index be4431f..ec2ec66 100644 --- a/routes/user.go +++ b/routes/user.go @@ -48,6 +48,7 @@ func SignUpOTP(rw http.ResponseWriter, req *http.Request) { if db.ExceedMaxOTP(t.Roll) { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp("too frequent otp requests", "please try again after 5 minutes")) + return } // Get OTP @@ -67,6 +68,7 @@ func SignUpOTP(rw http.ResponseWriter, req *http.Request) { if valid := c.Email(t, OTP, -1); valid != "" { rw.WriteHeader(http.StatusBadRequest) rw.Write(Rsp(valid, "Error in sending Email")) + return } @@ -133,6 +135,131 @@ func SignUp(rw http.ResponseWriter, req *http.Request) { rw.Write(Rsp("", fmt.Sprintf("User %s with roll %d is created", t.Name, t.Roll))) } } +// Endpoint to get OTP for Password +// POST: Roll-int, Email-string +func ForgotPassOTP(rw http.ResponseWriter, req *http.Request) { + if req.Method == "GET" { + rw.Write([]byte("Only POST request allowed")) + } else { + + // Input from request body + dec := json.NewDecoder(req.Body) + var inp c.User + err := dec.Decode(&inp) + if err != nil { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp(err.Error(), "Error in Decoding Data")) + return + } + + // Validate the request if it is empty + if valid := c.ValidateUserforOTP(inp); valid != "" { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp(valid, "Bad Request")) + return + } + + // Get user + t, err := db.GetUser(inp.Roll) + if err != nil { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp(err.Error(), "User Doesnot exist")) + return + } + + + // Check Spam + if db.ExceedMaxOTP_forgotpass(t.Roll) { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp("too frequent otp requests", "please try again after a week")) + return + } + + // Get OTP + OTP := c.GenerateOTP() + + // Hash and salt OTP + t.OTP = auth.HashAndSalt([]byte(OTP)) + + // Insert in DB + if valid := db.StoreOTP(t); valid != "" { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp(valid, "Error in Storing OTP")) + return + } + + // emailing OTP + if valid := c.Email(t, OTP, 1); valid != "" { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp(valid, "Error in sending Email")) + return + } + + + // Everything went well + rw.WriteHeader(http.StatusOK) + rw.Write(Rsp("", "email Sent")) + } +} + +// Endpoint to signup +// POST: Roll-int, OTP-string, Password-string +func ForgotPass(rw http.ResponseWriter, req *http.Request) { + if req.Method == "GET" { + rw.Write([]byte("Only POST request allowed")) + } else { + + // Input from request body + dec := json.NewDecoder(req.Body) + var t c.User + err := dec.Decode(&t) + + if err != nil { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp(err.Error(), "Error in Decoding Data")) + return + } + + // Validate the request if it is empty + if valid := c.ValidatePass(t); valid != "" { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp(valid, "Bad Request")) + return + } + + // Hash password + t.Password = auth.HashAndSalt([]byte(t.Password)) + + // check otp + hashotp, otpID, err := db.GetOTP(t.Roll) + if err != nil { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp(err.Error(), "Error in fetching OTP")) + return + } + + // check if otp is valid + if err := auth.Verify(t.OTP, hashotp); err != nil { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp(err.Error(), "Error in Verifying OTP")) + return + } + + defer db.MarkOTP(otpID) + + // Insert in DB + err = db.ChangePassword(t) + if err != nil { + rw.WriteHeader(http.StatusBadRequest) + rw.Write(Rsp(err.Error(), "Error in Changing Pass Up")) + return + } + + // Everything went well + rw.WriteHeader(http.StatusOK) + rw.Write(Rsp("", "Password reset succesful")) + } +} // Endpoint to signin // POST: Roll-int, Password-string @@ -241,9 +368,18 @@ func View(rw http.ResponseWriter, r *http.Request) { rw.Write(Rsp(err.Error(), "Server Error")) return } + usr.Password = "" + + wal, err := db.GetWallet(claims.Roll) + if err != nil { + rw.WriteHeader(http.StatusInternalServerError) + rw.Write(Rsp(err.Error(), "Server Error")) + return + } + rw.WriteHeader(http.StatusOK) res := c.RespData{ - Message: fmt.Sprintf("Hey, User %s!", usr.Name), + Message: fmt.Sprintf("Wallet Money is: %f", wal.Coins), Data: usr, } json.NewEncoder(rw).Encode(res)