Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error solved #11

Merged
merged 2 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
}
}}
>
<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
Loading