├── Dockerfile ├── README.md ├── app.go ├── app.yaml ├── docker-compose.yml ├── generateREADME.ts ├── go.mod ├── go.sum └── src ├── db └── db.go ├── middleware └── auth.go ├── models └── users.go ├── routes ├── allUsers.go ├── login.go ├── logout.go ├── profile.go ├── refreshToken.go ├── register.go └── struct.go └── utils ├── auth.go └── redis.go /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.12-alpine 2 | 3 | RUN apk update && apk upgrade && \ 4 | apk add --no-cache bash git openssh 5 | 6 | WORKDIR /app 7 | 8 | COPY go.mod go.sum ./ 9 | 10 | RUN go mod download 11 | 12 | COPY . . 13 | 14 | RUN go build -o main . 15 | 16 | EXPOSE 8080 17 | 18 | CMD ["./main"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OAuth2.0 API 2 | 3 | - **Golang** 4 | - **MongoDB** for storing data 5 | - **Redis** to Store JWT Metadata 6 | 7 | ## Base URL 8 | 9 | http://34.69.239.180 10 | 11 | ## Authentication Header 12 | 13 | `Bearer: ` 14 | 15 | ## Endpoints 16 | 17 | 18 | ### **Register** 19 | 20 | > **`POST`** [**/register**](http://34.69.239.180/register) 21 | 22 | **Request Body** 23 | 24 | ```json 25 | { 26 | "name": "YOUR NAME", 27 | "email": "EMAIL", 28 | "password": "PASSWORD" 29 | } 30 | ``` 31 | 32 | **Response** 33 | 34 | ```json 35 | { 36 | "code": 200 37 | } 38 | ``` 39 | 40 | 41 | ### **Login** 42 | 43 | > **`POST`** [**/login**](http://34.69.239.180/login) 44 | 45 | **Request Body** 46 | 47 | ```json 48 | { 49 | "email": "EMAIL", 50 | "password": "PASSWORD" 51 | } 52 | ``` 53 | 54 | **Response** 55 | 56 | ```json 57 | { 58 | "code": 200, 59 | "accessToken": "JWT TOKEN", 60 | "refreshToken": "JWT TOKEN" 61 | } 62 | ``` 63 | 64 | 65 | ### **Refresh Token** 66 | 67 | > **`POST`** [**/refresh**](http://34.69.239.180/refresh) 68 | 69 | **Request Body** 70 | 71 | ```json 72 | { 73 | "refreshToken": "JWT TOKEN" 74 | } 75 | ``` 76 | 77 | **Response** 78 | 79 | ```json 80 | { 81 | "accessToken": "JWT TOKEN" 82 | } 83 | ``` 84 | 85 | 86 | ### **Logout** 87 | 88 | > **`POST`** [**/logout**](http://34.69.239.180/logout) 89 | 90 | 91 | 92 | **Response** 93 | 94 | ```json 95 | { 96 | "code": 200 97 | } 98 | ``` 99 | 100 | 101 | ### **Get your profile** 102 | 103 | > **`GET`** [**/profile**](http://34.69.239.180/profile) 104 | 105 | 106 | 107 | **Response** 108 | 109 | ```json 110 | { 111 | "code": 200, 112 | "_id": "MONGODB ID", 113 | "name": "NAME", 114 | "email": "EMAIL" 115 | } 116 | ``` 117 | 118 | 119 | ### **Dump all profile** 120 | 121 | > **`GET`** [**/all**](http://34.69.239.180/all) 122 | 123 | 124 | 125 | **Response** 126 | 127 | ```json 128 | { 129 | "code": 200, 130 | "data": [ 131 | { 132 | "_id": "MONGODB ID", 133 | "name": "NAME", 134 | "email": "EMAIL" 135 | } 136 | ] 137 | } 138 | ``` 139 | 140 | -------------------------------------------------------------------------------- /app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "gawds/src/middleware" 8 | "gawds/src/routes" 9 | "gawds/src/utils" 10 | 11 | "github.com/gorilla/mux" 12 | ) 13 | 14 | func main() { 15 | utils.RedisInit() 16 | r := mux.NewRouter() 17 | r.Use(middleware.Middleware) 18 | r.HandleFunc("/login", routes.Login).Methods("POST") 19 | r.HandleFunc("/logout", routes.Logout).Methods("POST") 20 | r.HandleFunc("/register", routes.Register).Methods("POST") 21 | r.HandleFunc("/profile", routes.Profile).Methods("GET") 22 | r.HandleFunc("/refresh", routes.RefreshToken).Methods("POST") 23 | r.HandleFunc("/all", routes.GetAll).Methods("GET") 24 | 25 | r.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 26 | w.WriteHeader(http.StatusNotFound) 27 | w.Write([]byte("Route Not Found")) 28 | }) 29 | r.MethodNotAllowedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 30 | w.WriteHeader(http.StatusMethodNotAllowed) 31 | w.Write([]byte("Method Not Allowed")) 32 | }) 33 | r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 34 | w.WriteHeader(http.StatusOK) 35 | w.Write([]byte("Server Running")) 36 | }) 37 | log.Println("Server Stated") 38 | 39 | err := http.ListenAndServe(":8080", r) 40 | if err != nil { 41 | log.Fatalln("Error Occured", err) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app.yaml: -------------------------------------------------------------------------------- 1 | runtime: go115 2 | 3 | instance_class: F2 4 | 5 | env_variables: 6 | MONGO_URI: "mongodb+srv://user:user@mycluster.ddpqc.gcp.mongodb.net" 7 | 8 | handlers: 9 | - url: /.* 10 | script: auto 11 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | app: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | ports: 9 | - "80:8080" 10 | restart: unless-stopped 11 | depends_on: 12 | - redis 13 | environment: 14 | REDIS_DSN: redis:6379 15 | MONGO_URI: "mongodb+srv://user:user@mycluster.ddpqc.gcp.mongodb.net" 16 | networks: 17 | - backend 18 | 19 | redis: 20 | image: "redis:alpine" 21 | restart: unless-stopped 22 | networks: 23 | - backend 24 | 25 | networks: 26 | backend: 27 | -------------------------------------------------------------------------------- /generateREADME.ts: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | type ReadmeContent = { 4 | name: string; 5 | endpoint: string; 6 | method: "POST" | "GET"; 7 | request: {}; 8 | response: {}; 9 | }; 10 | const BASEURL = "http://34.69.239.180"; 11 | 12 | const content: ReadmeContent[] = [ 13 | { 14 | name: "Register", 15 | endpoint: "register", 16 | method: "POST", 17 | request: { 18 | name: "YOUR NAME", 19 | email: "EMAIL", 20 | password: "PASSWORD", 21 | }, 22 | response: { 23 | code: 200, 24 | }, 25 | }, 26 | { 27 | name: "Login", 28 | endpoint: "login", 29 | method: "POST", 30 | request: { 31 | email: "EMAIL", 32 | password: "PASSWORD", 33 | }, 34 | response: { 35 | code: 200, 36 | accessToken: "JWT TOKEN", 37 | refreshToken: "JWT TOKEN", 38 | }, 39 | }, 40 | { 41 | name: "Refresh Token", 42 | endpoint: "refresh", 43 | method: "POST", 44 | request: { 45 | refreshToken: "JWT TOKEN", 46 | }, 47 | response: { 48 | accessToken: "JWT TOKEN", 49 | }, 50 | }, 51 | { 52 | name: "Logout", 53 | endpoint: "logout", 54 | method: "POST", 55 | request: null, 56 | response: { 57 | code: 200, 58 | }, 59 | }, 60 | { 61 | name: "Get your profile", 62 | endpoint: "profile", 63 | method: "GET", 64 | request: null, 65 | response: { 66 | code: 200, 67 | _id: "MONGODB ID", 68 | name: "NAME", 69 | email: "EMAIL", 70 | }, 71 | }, 72 | { 73 | name: "Dump all profile", 74 | endpoint: "all", 75 | method: "GET", 76 | request: null, 77 | response: { 78 | code: 200, 79 | data: [ 80 | { 81 | _id: "MONGODB ID", 82 | name: "NAME", 83 | email: "EMAIL", 84 | }, 85 | ], 86 | }, 87 | }, 88 | ]; 89 | 90 | let md = `# OAuth2.0 API 91 | 92 | - **Golang** 93 | - **MongoDB** for storing data 94 | - **Redis** to Store JWT Metadata 95 | 96 | ## Base URL 97 | 98 | ${BASEURL} 99 | 100 | ## Authentication Header 101 | 102 | \`Bearer: \` 103 | 104 | ## Endpoints 105 | 106 | `; 107 | 108 | content.forEach((e) => { 109 | md += ` 110 | ### **${e.name}** 111 | 112 | > **\`${e.method}\`** [**/${e.endpoint}**](${BASEURL}/${e.endpoint}) 113 | 114 | ${ 115 | e.request 116 | ? `**Request Body** 117 | 118 | \`\`\`json 119 | ${JSON.stringify(e.request, null, 2)} 120 | \`\`\`` 121 | : "" 122 | } 123 | 124 | **Response** 125 | 126 | \`\`\`json 127 | ${JSON.stringify(e.response, null, 2)} 128 | \`\`\` 129 | 130 | `; 131 | }); 132 | 133 | fs.writeFileSync("README.md", md); 134 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module gawds 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/badoux/checkmail v1.2.1 // indirect 7 | github.com/dgrijalva/jwt-go v3.2.0+incompatible 8 | github.com/go-playground/universal-translator v0.17.0 // indirect 9 | github.com/go-playground/validator v9.31.0+incompatible // indirect 10 | github.com/go-redis/redis v6.15.9+incompatible 11 | github.com/go-redis/redis/v7 v7.4.0 // indirect 12 | github.com/gorilla/mux v1.8.0 13 | github.com/gorilla/sessions v1.2.1 14 | github.com/leodido/go-urn v1.2.1 // indirect 15 | github.com/softbrewery/gojoi v0.0.0-20180423202125-34d5e1054ec7 // indirect 16 | github.com/twinj/uuid v1.0.0 // indirect 17 | go.mongodb.org/mongo-driver v1.5.1 18 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk= 3 | github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= 4 | github.com/badoux/checkmail v1.2.1 h1:TzwYx5pnsV6anJweMx2auXdekBwGr/yt1GgalIx9nBQ= 5 | github.com/badoux/checkmail v1.2.1/go.mod h1:XroCOBU5zzZJcLvgwU15I+2xXyCdTWXyR9MGfRhBYy0= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 8 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 10 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 11 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 12 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 13 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 14 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 15 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 16 | github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA= 17 | github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig= 18 | github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= 19 | github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= 20 | github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4= 21 | github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= 22 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 23 | github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= 24 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 25 | github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= 26 | github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= 27 | github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= 28 | github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= 29 | github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= 30 | github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= 31 | github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= 32 | github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= 33 | github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= 34 | github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= 35 | github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= 36 | github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= 37 | github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= 38 | github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= 39 | github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= 40 | github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= 41 | github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= 42 | github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= 43 | github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= 44 | github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= 45 | github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= 46 | github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= 47 | github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= 48 | github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= 49 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 50 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 51 | github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= 52 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 53 | github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= 54 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 55 | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= 56 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 57 | github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= 58 | github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= 59 | github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= 60 | github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= 61 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 62 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 63 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 64 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 65 | github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= 66 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 67 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= 68 | github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= 69 | github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= 70 | github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M= 71 | github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 72 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 73 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 74 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 75 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 76 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 77 | github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= 78 | github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= 79 | github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= 80 | github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= 81 | github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= 82 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 83 | github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 84 | github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 85 | github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= 86 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 87 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 88 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 89 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 90 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 91 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 92 | github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 93 | github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 94 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 95 | github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 96 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 97 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 98 | github.com/softbrewery/gojoi v0.0.0-20180423202125-34d5e1054ec7 h1:JYS6bLbT96aLeYtdmAdZ5fhvwLrK4JRao4K0bK7N5lI= 99 | github.com/softbrewery/gojoi v0.0.0-20180423202125-34d5e1054ec7/go.mod h1:5w5CHxUYoWjrsl3+TPI1aXnuX+2d0OjrLBTsrKYd1X8= 100 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 101 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 102 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 103 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 104 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 105 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 106 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 107 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 108 | github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= 109 | github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= 110 | github.com/twinj/uuid v1.0.0 h1:fzz7COZnDrXGTAOHGuUGYd6sG+JMq+AoE7+Jlu0przk= 111 | github.com/twinj/uuid v1.0.0/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY= 112 | github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= 113 | github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= 114 | github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= 115 | github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= 116 | github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= 117 | github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= 118 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= 119 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= 120 | go.mongodb.org/mongo-driver v1.5.1 h1:9nOVLGDfOaZ9R0tBumx/BcuqkbFpyTCU2r/Po7A2azI= 121 | go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw= 122 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 123 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 124 | golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 125 | golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= 126 | golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 127 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= 128 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 129 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 130 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 131 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 132 | golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 133 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 134 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 135 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 136 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 137 | golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 138 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 139 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= 140 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 141 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 142 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 143 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 144 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 145 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 146 | golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 147 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 148 | golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 149 | golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 150 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 151 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 152 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 153 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 154 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 155 | golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= 156 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 157 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 158 | golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 159 | golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 160 | golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 161 | golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 162 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 163 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 164 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 165 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 166 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 167 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 168 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 169 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 170 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 171 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 172 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 173 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 174 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 175 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 176 | -------------------------------------------------------------------------------- /src/db/db.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "context" 5 | "os" 6 | "sync" 7 | 8 | "go.mongodb.org/mongo-driver/mongo" 9 | "go.mongodb.org/mongo-driver/mongo/options" 10 | ) 11 | 12 | var clientInstance *mongo.Client 13 | 14 | var clientInstanceError error 15 | 16 | var mongoOnce sync.Once 17 | 18 | const ( 19 | DB = "gawds" 20 | USERS = "users" 21 | ) 22 | 23 | func GetMongoClient() (*mongo.Client, error) { 24 | connString := os.Getenv("MONGO_URI") 25 | 26 | if connString == "" { 27 | connString = "mongodb://localhost:27017" 28 | } 29 | mongoOnce.Do(func() { 30 | clientOptions := options.Client().ApplyURI(connString) 31 | client, err := mongo.Connect(context.TODO(), clientOptions) 32 | if err != nil { 33 | clientInstanceError = err 34 | } 35 | err = client.Ping(context.TODO(), nil) 36 | if err != nil { 37 | clientInstanceError = err 38 | } 39 | clientInstance = client 40 | }) 41 | return clientInstance, clientInstanceError 42 | } 43 | -------------------------------------------------------------------------------- /src/middleware/auth.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "context" 5 | "gawds/src/utils" 6 | "net/http" 7 | ) 8 | 9 | func Middleware(next http.Handler) http.Handler { 10 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 11 | metadata, err := utils.ExtractTokenMetadata(r) 12 | if err != nil { 13 | next.ServeHTTP(w, r) 14 | return 15 | } 16 | 17 | ctx := context.WithValue(r.Context(), "id", metadata.UserId) 18 | 19 | next.ServeHTTP(w, r.WithContext(ctx)) 20 | 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /src/models/users.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "go.mongodb.org/mongo-driver/bson/primitive" 4 | 5 | type User struct { 6 | Uid primitive.ObjectID `json:"_id" bson:"_id"` 7 | Name string `json:"name" bson:"name"` 8 | Email string `json:"email" bson:"email"` 9 | Password string `json:"password" bson:"password"` 10 | } 11 | -------------------------------------------------------------------------------- /src/routes/allUsers.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "gawds/src/db" 7 | "log" 8 | "net/http" 9 | 10 | "go.mongodb.org/mongo-driver/bson" 11 | ) 12 | 13 | func GetAll(w http.ResponseWriter, r *http.Request) { 14 | uid, _ := r.Context().Value("id").(string) 15 | 16 | if uid == "" { 17 | w.WriteHeader(http.StatusUnauthorized) 18 | json.NewEncoder(w).Encode(Response{ 19 | Code: 401, 20 | Message: "Unauthorized", 21 | }) 22 | return 23 | } 24 | 25 | client, err := db.GetMongoClient() 26 | 27 | if err != nil { 28 | json.NewEncoder(w).Encode(Response{ 29 | Code: 400, 30 | Message: "Connection Not Established", 31 | }) 32 | return 33 | } 34 | 35 | col := client.Database(db.DB).Collection(db.USERS) 36 | 37 | cur, err := col.Find(context.TODO(), bson.D{{}}) 38 | if err != nil { 39 | log.Fatal(err) 40 | } 41 | var results []UserData 42 | 43 | for cur.Next(context.TODO()) { 44 | 45 | var elem UserData 46 | err := cur.Decode(&elem) 47 | if err != nil { 48 | log.Fatal(err) 49 | } 50 | 51 | results = append(results, elem) 52 | 53 | } 54 | 55 | if err := cur.Err(); err != nil { 56 | log.Fatal(err) 57 | } 58 | 59 | cur.Close(context.TODO()) 60 | 61 | json.NewEncoder(w).Encode(AllUserResponse{ 62 | Code: 400, 63 | Result: results, 64 | }) 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/routes/login.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "gawds/src/db" 7 | "gawds/src/models" 8 | "gawds/src/utils" 9 | "net/http" 10 | 11 | "github.com/softbrewery/gojoi/pkg/joi" 12 | "go.mongodb.org/mongo-driver/bson" 13 | "go.mongodb.org/mongo-driver/bson/primitive" 14 | "golang.org/x/crypto/bcrypt" 15 | ) 16 | 17 | func Login(w http.ResponseWriter, r *http.Request) { 18 | var user LoginBody 19 | var loggedUser models.User 20 | 21 | client, connErr := db.GetMongoClient() 22 | 23 | emailError := joi.Validate(user.Email, joi.String().Email(nil)) 24 | passwordError := joi.Validate(user.Password, joi.String().Min(6)) 25 | 26 | if emailError != nil || passwordError != nil { 27 | json.NewEncoder(w).Encode(Response{ 28 | Code: 400, 29 | Message: "Invalid Body with error(s):" + emailError.Error() + passwordError.Error(), 30 | }) 31 | return 32 | } 33 | 34 | if connErr != nil { 35 | w.WriteHeader(http.StatusBadGateway) 36 | json.NewEncoder(w).Encode(Response{ 37 | Code: 400, 38 | Message: "Connection Not Established", 39 | }) 40 | return 41 | } 42 | 43 | jsonErr := json.NewDecoder(r.Body).Decode(&user) 44 | 45 | if jsonErr != nil { 46 | w.WriteHeader(http.StatusBadRequest) 47 | json.NewEncoder(w).Encode(Response{ 48 | Code: 400, 49 | Message: "Invalid Body", 50 | }) 51 | return 52 | } 53 | 54 | collection := client.Database(db.DB).Collection(db.USERS) 55 | 56 | res := collection.FindOne(context.TODO(), bson.D{primitive.E{Key: "email", Value: user.Email}}) 57 | 58 | if res.Err() == nil { 59 | res.Decode(&loggedUser) 60 | 61 | err := bcrypt.CompareHashAndPassword([]byte(loggedUser.Password), []byte(user.Password)) 62 | 63 | if err != nil { 64 | w.WriteHeader(http.StatusForbidden) 65 | json.NewEncoder(w).Encode(map[string]interface{}{ 66 | "code": 400, 67 | "Message": "Login Failed", 68 | }) 69 | return 70 | } 71 | 72 | tokens, err := utils.CreateToken(loggedUser.Uid.Hex()) 73 | if err != nil { 74 | json.NewEncoder(w).Encode(map[string]interface{}{ 75 | "code": 400, 76 | "Message": "Unable to create token", 77 | }) 78 | return 79 | } 80 | redisError := utils.CreateAuth(loggedUser.Uid.Hex(), tokens) 81 | 82 | if redisError != nil { 83 | w.WriteHeader(http.StatusInternalServerError) 84 | json.NewEncoder(w).Encode(map[string]interface{}{ 85 | "code": 400, 86 | "Message": "Unable to save token", 87 | }) 88 | return 89 | } 90 | json.NewEncoder(w).Encode(LoginResponse{ 91 | Code: 200, 92 | Message: "Login Done", 93 | RefreshToken: tokens.RefreshToken, 94 | AccessToken: tokens.AccessToken, 95 | }) 96 | } else { 97 | w.WriteHeader(http.StatusForbidden) 98 | json.NewEncoder(w).Encode(Response{ 99 | Code: 400, 100 | Message: "Login Failed", 101 | }) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/routes/logout.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "encoding/json" 5 | "gawds/src/utils" 6 | "net/http" 7 | ) 8 | 9 | func Logout(w http.ResponseWriter, r *http.Request) { 10 | metadata, err := utils.ExtractTokenMetadata(r) 11 | if err != nil { 12 | w.WriteHeader(http.StatusUnauthorized) 13 | json.NewEncoder(w).Encode(Response{ 14 | Code: 401, 15 | Message: "Unauthorized", 16 | }) 17 | return 18 | } 19 | delErr := utils.DeleteTokens(metadata) 20 | if delErr != nil { 21 | json.NewEncoder(w).Encode(Response{ 22 | Code: 500, 23 | Message: "Unable to log you out", 24 | }) 25 | return 26 | } 27 | json.NewEncoder(w).Encode(Response{ 28 | Code: 200, 29 | Message: "Done", 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /src/routes/profile.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "gawds/src/db" 7 | "net/http" 8 | 9 | "go.mongodb.org/mongo-driver/bson" 10 | "go.mongodb.org/mongo-driver/bson/primitive" 11 | ) 12 | 13 | func Profile(w http.ResponseWriter, r *http.Request) { 14 | uid, _ := r.Context().Value("id").(string) 15 | 16 | if uid == "" { 17 | w.WriteHeader(http.StatusUnauthorized) 18 | json.NewEncoder(w).Encode(Response{ 19 | Code: 401, 20 | Message: "Unauthorized", 21 | }) 22 | return 23 | } 24 | 25 | client, err := db.GetMongoClient() 26 | 27 | var user UserData 28 | 29 | if err != nil { 30 | json.NewEncoder(w).Encode(Response{ 31 | Code: 400, 32 | Message: "Connection Not Established", 33 | }) 34 | return 35 | } 36 | 37 | collection := client.Database(db.DB).Collection(db.USERS) 38 | 39 | docID, _ := primitive.ObjectIDFromHex(uid) 40 | 41 | res := collection.FindOne(context.TODO(), bson.D{bson.E{Key: "_id", Value: docID}}) 42 | 43 | err = res.Decode(&user) 44 | 45 | if err != nil { 46 | json.NewEncoder(w).Encode(Response{ 47 | Code: 400, 48 | Message: "User Not Logged in", 49 | }) 50 | } else { 51 | json.NewEncoder(w).Encode(UserResponse{ 52 | Code: 200, 53 | Message: "Success", 54 | Result: user, 55 | }) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/routes/refreshToken.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "gawds/src/utils" 7 | "net/http" 8 | "os" 9 | 10 | "github.com/dgrijalva/jwt-go" 11 | ) 12 | 13 | type Token struct { 14 | RefreshToken string `json:"refreshToken"` 15 | } 16 | 17 | func RefreshToken(w http.ResponseWriter, r *http.Request) { 18 | var bodyToken Token 19 | 20 | err := json.NewDecoder(r.Body).Decode(&bodyToken) 21 | if err != nil { 22 | json.NewEncoder(w).Encode(Response{ 23 | Code: 400, 24 | Message: "Invalid Body", 25 | }) 26 | return 27 | } 28 | refreshToken := bodyToken.RefreshToken 29 | 30 | os.Setenv("REFRESH_SECRET", "mcmvmkmsdnfsdmfdsjf") 31 | token, _ := jwt.Parse(refreshToken, func(token *jwt.Token) (interface{}, error) { 32 | if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { 33 | return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) 34 | } 35 | return []byte(os.Getenv("REFRESH_SECRET")), nil 36 | }) 37 | if err != nil { 38 | fmt.Println("the error: ", err) 39 | w.WriteHeader(http.StatusUnauthorized) 40 | json.NewEncoder(w).Encode(Response{ 41 | Code: 400, 42 | Message: "Refresh token expired", 43 | }) 44 | return 45 | } 46 | if _, ok := token.Claims.(jwt.Claims); !ok && !token.Valid { 47 | w.WriteHeader(http.StatusUnauthorized) 48 | json.NewEncoder(w).Encode(Response{ 49 | Code: 400, 50 | Message: err.Error(), 51 | }) 52 | return 53 | } 54 | claims, ok := token.Claims.(jwt.MapClaims) //the token claims should conform to MapClaims 55 | if ok && token.Valid { 56 | refreshUuid, ok := claims["refresh_uuid"].(string) //convert the interface to string 57 | if !ok { 58 | 59 | w.WriteHeader(http.StatusUnprocessableEntity) 60 | 61 | json.NewEncoder(w).Encode(map[string]interface{}{ 62 | "code": 400, 63 | "Message": "Unauthorized", 64 | }) 65 | return 66 | } 67 | userId := claims["user_id"].(string) 68 | 69 | deleted, delErr := utils.DeleteAuth(refreshUuid) 70 | if delErr != nil || deleted == 0 { //if any goes wrong 71 | w.WriteHeader(http.StatusUnauthorized) 72 | 73 | json.NewEncoder(w).Encode(map[string]interface{}{ 74 | "code": 400, 75 | "Message": "Unauthorized", 76 | }) 77 | return 78 | } 79 | //Create new pairs of refresh and access tokens 80 | ts, createErr := utils.CreateToken(userId) 81 | if createErr != nil { 82 | w.WriteHeader(http.StatusForbidden) 83 | json.NewEncoder(w).Encode(map[string]interface{}{ 84 | "code": 400, 85 | "Message": "Unable to save token", 86 | }) 87 | return 88 | } 89 | //save the tokens metadata to redis 90 | saveErr := utils.CreateAuth(userId, ts) 91 | if saveErr != nil { 92 | json.NewEncoder(w).Encode(map[string]interface{}{ 93 | "code": 400, 94 | "Message": "Unable to save token", 95 | }) 96 | return 97 | } 98 | tokens := map[string]interface{}{ 99 | "code": 200, 100 | "accessToken": ts.AccessToken, 101 | "refreshToken": ts.RefreshToken, 102 | } 103 | json.NewEncoder(w).Encode(tokens) 104 | } else { 105 | json.NewEncoder(w).Encode(map[string]interface{}{ 106 | "code": 400, 107 | "Message": "Refresh Expired", 108 | }) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/routes/register.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "gawds/src/db" 7 | "net/http" 8 | 9 | "github.com/softbrewery/gojoi/pkg/joi" 10 | "go.mongodb.org/mongo-driver/bson" 11 | "go.mongodb.org/mongo-driver/bson/primitive" 12 | "go.mongodb.org/mongo-driver/mongo" 13 | "golang.org/x/crypto/bcrypt" 14 | ) 15 | 16 | type newUser struct { 17 | Name string `json:"name"` 18 | Email string `json:"email" validate:"required,email"` 19 | Password string `json:"password"` 20 | } 21 | 22 | func Register(w http.ResponseWriter, r *http.Request) { 23 | var newUser newUser 24 | 25 | err := json.NewDecoder(r.Body).Decode(&newUser) 26 | if err != nil { 27 | json.NewEncoder(w).Encode(Response{ 28 | Code: 400, 29 | Message: "Invalid Body", 30 | }) 31 | return 32 | } 33 | 34 | nameError := joi.Validate(newUser.Email, joi.String().Email(nil)) 35 | emailError := joi.Validate(newUser.Email, joi.String().Email(nil)) 36 | passwordError := joi.Validate(newUser.Password, joi.String().Min(6)) 37 | 38 | if emailError != nil || passwordError != nil || nameError != nil { 39 | json.NewEncoder(w).Encode(Response{ 40 | Code: 400, 41 | Message: "Invalid Body with error(s):" + emailError.Error() + passwordError.Error() + nameError.Error(), 42 | }) 43 | return 44 | } 45 | 46 | client, err := db.GetMongoClient() 47 | 48 | if err != nil { 49 | json.NewEncoder(w).Encode(Response{ 50 | Code: 400, 51 | Message: "Connection Not Established", 52 | }) 53 | return 54 | } 55 | 56 | collection := client.Database(db.DB).Collection(db.USERS) 57 | 58 | res := collection.FindOne(context.TODO(), bson.D{primitive.E{Key: "email", Value: newUser.Email}}) 59 | 60 | if res.Err() == mongo.ErrNoDocuments { 61 | 62 | hash, _ := bcrypt.GenerateFromPassword([]byte(newUser.Password), bcrypt.MinCost) 63 | 64 | newUser.Password = string(hash) 65 | 66 | _, err = collection.InsertOne(context.TODO(), newUser) 67 | 68 | if err != nil { 69 | json.NewEncoder(w).Encode(Response{ 70 | Code: 400, 71 | Message: err.Error(), 72 | }) 73 | return 74 | } 75 | json.NewEncoder(w).Encode(Response{ 76 | Code: 200, 77 | Message: "Successfully registered", 78 | }) 79 | 80 | } else { 81 | json.NewEncoder(w).Encode(Response{ 82 | Code: 400, 83 | Message: "User Already Exists", 84 | }) 85 | return 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/routes/struct.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "go.mongodb.org/mongo-driver/bson/primitive" 5 | ) 6 | 7 | type Response struct { 8 | Code int `json:"code"` 9 | Message string `json:"message"` 10 | } 11 | 12 | type UserData struct { 13 | Uid primitive.ObjectID `json:"_id" bson:"_id"` 14 | Name string `json:"name" bson:"name"` 15 | Email string `json:"email" bson:"email"` 16 | } 17 | type UserResponse struct { 18 | Code int `json:"code"` 19 | Message string `json:"message"` 20 | Result UserData `json:"result"` 21 | } 22 | 23 | type AllUserResponse struct { 24 | Code int `json:"code"` 25 | Result []UserData `json:"result"` 26 | } 27 | 28 | type LoginBody struct { 29 | Email string `json:"email"` 30 | Password string `json:"password"` 31 | } 32 | 33 | type LoginResponse struct { 34 | Code int `json:"code"` 35 | Message string `json:"message"` 36 | RefreshToken string `json:"refreshToken"` 37 | AccessToken string `json:"accessToken"` 38 | } 39 | type RefreshTokenResponse struct { 40 | AccessToken string `json:"accessToken"` 41 | } 42 | -------------------------------------------------------------------------------- /src/utils/auth.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net/http" 7 | "strings" 8 | "time" 9 | 10 | "github.com/dgrijalva/jwt-go" 11 | "github.com/twinj/uuid" 12 | ) 13 | 14 | type User struct { 15 | ID int64 `json:"id"` 16 | Username string `json:"username"` 17 | Password string `json:"password"` 18 | } 19 | 20 | var user = User{ 21 | ID: 1, 22 | Username: "username", 23 | Password: "password", 24 | } 25 | 26 | type AccessDetails struct { 27 | AccessUuid string 28 | UserId string 29 | } 30 | 31 | type TokenDetails struct { 32 | AccessToken string 33 | RefreshToken string 34 | AccessUuid string 35 | RefreshUuid string 36 | AtExpires int64 37 | RtExpires int64 38 | } 39 | 40 | func CreateToken(userid string) (*TokenDetails, error) { 41 | td := &TokenDetails{} 42 | td.AtExpires = time.Now().Add(time.Minute * 15).Unix() 43 | td.AccessUuid = uuid.NewV4().String() 44 | 45 | td.RtExpires = time.Now().Add(time.Hour * 24 * 7).Unix() 46 | td.RefreshUuid = td.AccessUuid + "++" + (userid) 47 | 48 | var err error 49 | atClaims := jwt.MapClaims{} 50 | atClaims["authorized"] = true 51 | atClaims["access_uuid"] = td.AccessUuid 52 | atClaims["user_id"] = userid 53 | atClaims["exp"] = td.AtExpires 54 | at := jwt.NewWithClaims(jwt.SigningMethodHS256, atClaims) 55 | td.AccessToken, err = at.SignedString([]byte("jdnfksdmfksd")) 56 | if err != nil { 57 | return nil, err 58 | } 59 | rtClaims := jwt.MapClaims{} 60 | rtClaims["refresh_uuid"] = td.RefreshUuid 61 | rtClaims["user_id"] = userid 62 | rtClaims["exp"] = td.RtExpires 63 | rt := jwt.NewWithClaims(jwt.SigningMethodHS256, rtClaims) 64 | td.RefreshToken, err = rt.SignedString([]byte("mcmvmkmsdnfsdmfdsjf")) 65 | if err != nil { 66 | return nil, err 67 | } 68 | return td, nil 69 | } 70 | 71 | func CreateAuth(userid string, td *TokenDetails) error { 72 | at := time.Unix(td.AtExpires, 0) 73 | rt := time.Unix(td.RtExpires, 0) 74 | now := time.Now() 75 | 76 | errAccess := client.Set(td.AccessUuid, (userid), at.Sub(now)).Err() 77 | if errAccess != nil { 78 | return errAccess 79 | } 80 | errRefresh := client.Set(td.RefreshUuid, (userid), rt.Sub(now)).Err() 81 | if errRefresh != nil { 82 | return errRefresh 83 | } 84 | return nil 85 | } 86 | 87 | func ExtractToken(r *http.Request) string { 88 | bearToken := r.Header.Get("Authorization") 89 | strArr := strings.Split(bearToken, " ") 90 | if len(strArr) == 2 { 91 | return strArr[1] 92 | } 93 | return "" 94 | } 95 | 96 | func VerifyToken(r *http.Request) (*jwt.Token, error) { 97 | tokenString := ExtractToken(r) 98 | token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { 99 | return []byte("jdnfksdmfksd"), nil 100 | }) 101 | 102 | if err != nil { 103 | return nil, err 104 | } 105 | 106 | return token, nil 107 | } 108 | 109 | func TokenValid(r *http.Request) error { 110 | token, err := VerifyToken(r) 111 | if err != nil { 112 | return err 113 | } 114 | if _, ok := token.Claims.(jwt.Claims); !ok || !token.Valid { 115 | return err 116 | } 117 | return nil 118 | } 119 | 120 | func ExtractTokenMetadata(r *http.Request) (*AccessDetails, error) { 121 | token, err := VerifyToken(r) 122 | if err != nil { 123 | return nil, err 124 | } 125 | claims, ok := token.Claims.(jwt.MapClaims) 126 | if ok && token.Valid { 127 | accessUuid, ok := claims["access_uuid"].(string) 128 | if !ok { 129 | return nil, err 130 | } 131 | if err != nil { 132 | return nil, err 133 | } 134 | return &AccessDetails{ 135 | AccessUuid: accessUuid, 136 | UserId: claims["user_id"].(string), 137 | }, nil 138 | } 139 | return nil, err 140 | } 141 | 142 | func FetchAuth(authD *AccessDetails) (string, error) { 143 | userID, err := client.Get(authD.AccessUuid).Result() 144 | if err != nil { 145 | return "", err 146 | } 147 | if authD.UserId != userID { 148 | return "", errors.New("unauthorized") 149 | } 150 | return userID, nil 151 | } 152 | 153 | func DeleteAuth(givenUuid string) (int, error) { 154 | _, err := client.Del(givenUuid).Result() 155 | if err != nil { 156 | return 0, err 157 | } 158 | return 1, nil 159 | } 160 | 161 | func DeleteTokens(authD *AccessDetails) error { 162 | 163 | refreshUuid := fmt.Sprintf("%s++%d", authD.AccessUuid, authD.UserId) 164 | deletedAt, err := client.Del(authD.AccessUuid).Result() 165 | if err != nil { 166 | return err 167 | } 168 | deletedRt, err := client.Del(refreshUuid).Result() 169 | if err != nil { 170 | return err 171 | } 172 | if deletedAt != 1 || deletedRt != 1 { 173 | return errors.New("something went wrong") 174 | } 175 | return nil 176 | } 177 | -------------------------------------------------------------------------------- /src/utils/redis.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/go-redis/redis" 7 | ) 8 | 9 | var client *redis.Client 10 | 11 | func RedisInit() { 12 | dsn := os.Getenv("REDIS_DSN") 13 | if len(dsn) == 0 { 14 | dsn = "localhost:6379" 15 | } 16 | client = redis.NewClient(&redis.Options{ 17 | Addr: dsn, 18 | }) 19 | _, err := client.Ping().Result() 20 | if err != nil { 21 | panic(err) 22 | } 23 | } 24 | --------------------------------------------------------------------------------