Skip to content

Commit

Permalink
Merge pull request #11 from PreetinderSinghBadesha/ErrorSolved
Browse files Browse the repository at this point in the history
Error solved
  • Loading branch information
PreetinderSinghBadesha authored Jul 4, 2024
2 parents 1e46b79 + dd0a14f commit 086af5f
Show file tree
Hide file tree
Showing 14 changed files with 432 additions and 49 deletions.
Binary file added backend/bin/api
Binary file not shown.
12 changes: 12 additions & 0 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,16 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/labstack/echo/v4 v4.12.0 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/rs/cors v1.11.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
)
27 changes: 27 additions & 0 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,34 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8=
github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po=
github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
30 changes: 21 additions & 9 deletions backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
router "github.com/MicrosoftStudentChapter/Link-Generator/pkg/router"
"github.com/gorilla/mux"
"github.com/redis/go-redis/v9"
"github.com/rs/cors"
)

func main() {
Expand All @@ -31,34 +32,45 @@ func main() {
fmt.Println("Redis [PING]: ", res)

r := mux.NewRouter()

// Define routes
r.HandleFunc("/links/all", router.GetAllLinks).Methods(http.MethodOptions, http.MethodGet)
r.HandleFunc("/generate-token", auth.GenerateJWT).Methods(http.MethodOptions, http.MethodGet)
r.Handle("/login", auth.TokenRequired(http.HandlerFunc(auth.ProtectedRoute))).Methods(http.MethodOptions, http.MethodGet)
r.HandleFunc("/admin", auth.ProtectedRoute).Methods(http.MethodOptions, http.MethodGet)
r.HandleFunc("/register", auth.Register).Methods(http.MethodOptions, http.MethodPost)
r.HandleFunc("/show/users", auth.ShowUsers).Methods(http.MethodOptions, http.MethodGet)
r.HandleFunc("/login", auth.Login).Methods(http.MethodOptions, http.MethodGet)
r.HandleFunc("/show", auth.ShowUsers).Methods(http.MethodOptions, http.MethodPost)
r.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Service is Alive"))
}).Methods(http.MethodOptions, http.MethodGet)
r.HandleFunc("/add-link", router.AddLink).Methods(http.MethodOptions, http.MethodPost)
r.HandleFunc("/{link}", router.HandleRouting).Methods(http.MethodOptions, http.MethodGet)

// Middlewares
r.Use(LoggingMiddleware)
r.Use(mux.CORSMethodMiddleware(r))
r.Use(HandlePreflight)

fmt.Println("Server started at port 4000")
// Configure CORS
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:5173"}, // Change this to your front-end URL
AllowCredentials: true,
AllowedMethods: []string{"GET", "POST"},
AllowedHeaders: []string{"Authorization"},
})

http.ListenAndServe(":4000", r)
handler := c.Handler(r)
fmt.Println("Server started at port 4000")
http.ListenAndServe(":4000", handler)
}

// Middlewares

func HandlePreflight(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Access-Control-Allow-Origin", "http://localhost:5173") // Change this to your frontend URL
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Credentials", "true")

if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusOK)
return
Expand Down
105 changes: 80 additions & 25 deletions backend/pkg/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,36 @@ import (
"os"
"time"

"github.com/dgrijalva/jwt-go"
cookie "github.com/MicrosoftStudentChapter/Link-Generator/pkg/cookies"

"github.com/golang-jwt/jwt"
"golang.org/x/crypto/bcrypt"
)

var jwtKey = []byte(os.Getenv("JWT_SECRET"))
var users = map[string]string{}

type User struct {
ID string
Username string
Password string
}

type Response struct {
Status string `json:"status"`
RedirectUrl string `json:"redirectUrl,omitempty"`
Message string `json:"message,omitempty"`
}

type Claims struct {
Username string "json:username"
jwt.StandardClaims
}

func GenerateJWT(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
func GenerateTokenAndSetCookies(w http.ResponseWriter, r *http.Request, username string) string {
if username == "" {
http.Error(w, "Username is required", http.StatusBadRequest)
return
return ""
}

expirationTime := time.Now().Add(30 * time.Minute)
Expand All @@ -39,11 +53,12 @@ func GenerateJWT(w http.ResponseWriter, r *http.Request) {
tokenString, err := token.SignedString(jwtKey)
if err != nil {
http.Error(w, "Could not generate token", http.StatusInternalServerError)
return
return ""
}

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"token": tokenString})
cookie.SetTokenCookie("access-token", tokenString, expirationTime, w)

return tokenString
}

func ValidateJWT(tokenString string) (string, error) {
Expand All @@ -63,29 +78,47 @@ func ValidateJWT(tokenString string) (string, error) {
return claims.Username, nil
}

func TokenRequired(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tokenString := r.Header.Get("Authorization")
if tokenString == "" {
http.Error(w, "Token is missing", http.StatusForbidden)
return
}
func Login(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
password := r.URL.Query().Get("password")

var loggedInUser *User

username, err := ValidateJWT(tokenString)
if err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
users := GetUsers()

for _, user := range users {
if user.Username != username {
continue
}
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err == nil {
loggedInUser = user
break
}
}

r.Header.Set("username", username)
next.ServeHTTP(w, r)
})
}
if loggedInUser == nil {
w.WriteHeader(http.StatusForbidden)
json.NewEncoder(w).Encode(Response{Status: "fail", Message: "Invalid Login"})
return
}
tokenString := GenerateTokenAndSetCookies(w, r, username)

func ProtectedRoute(w http.ResponseWriter, r *http.Request) {
url := "http://localhost:5173/Adminpage"
if tokenString == "" {
w.WriteHeader(http.StatusForbidden)
json.NewEncoder(w).Encode(Response{Status: "fail", Message: "Token is missing"})
return
}

_, err := ValidateJWT(tokenString)
if err != nil {
w.WriteHeader(http.StatusForbidden)
json.NewEncoder(w).Encode(Response{Status: "fail", Message: err.Error(), RedirectUrl: "http://localhost:5173/error"})
return
}

url := "http://localhost:5173/link-gen"
fmt.Printf("Route Url: " + url)
http.Redirect(w, r, url, http.StatusSeeOther)
json.NewEncoder(w).Encode(Response{Status: "success", RedirectUrl: url})
}

func Register(w http.ResponseWriter, r *http.Request) {
Expand All @@ -111,6 +144,28 @@ func Register(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"message": "User registered successfully"})
}

func GetUsers() []*User {
password, _ := bcrypt.GenerateFromPassword([]byte("12345"), 8)

return []*User{
{
ID: "1",
Username: "Preet",
Password: string(password),
},
{
ID: "2",
Username: "Jeevant",
Password: string(password),
},
{
ID: "3",
Username: "Akshat",
Password: string(password),
},
}
}

func ShowUsers(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
Expand Down
20 changes: 20 additions & 0 deletions backend/pkg/cookies/cookies.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cookies

import (
"net/http"
"time"
)

func SetTokenCookie(name, token string, expiration time.Time, w http.ResponseWriter) {
cookie := &http.Cookie{
Name: name,
Value: token,
Expires: expiration,
Path: "/",
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
Secure: false,
}

http.SetCookie(w, cookie)
}
41 changes: 40 additions & 1 deletion frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"axios": "^1.6.8",
"dayjs": "^1.11.10",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-router-dom": "^6.23.1"
},
"devDependencies": {
"@types/react": "^18.2.64",
Expand Down
14 changes: 11 additions & 3 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import { Container } from '@mui/material';

import MainContentSection from './Maincontent';
import "./App.css"
import LoginPageSection from './loginPage';
import ErrorPageSection from './errorPage';
import "./App.css";

const App = () => {
return (
<div className='app'>
Expand All @@ -19,10 +22,15 @@ const App = () => {
}
}}
>
<MainContentSection />
<Routes>

Check failure on line 25 in frontend/src/App.jsx

View workflow job for this annotation

GitHub Actions / build

'Routes' is not defined
<Route path="/" element={<LoginPageSection />} />

Check failure on line 26 in frontend/src/App.jsx

View workflow job for this annotation

GitHub Actions / build

'Route' is not defined
<Route path="/link-gen" element={<MainContentSection />} />

Check failure on line 27 in frontend/src/App.jsx

View workflow job for this annotation

GitHub Actions / build

'Route' is not defined
<Route path="/error" element={<ErrorPageSection />} />

Check failure on line 28 in frontend/src/App.jsx

View workflow job for this annotation

GitHub Actions / build

'Route' is not defined
</Routes>
</Container>

</div>
);
};

export default App;
export default App;
Loading

0 comments on commit 086af5f

Please sign in to comment.