added registration
This commit is contained in:
parent
0edb234718
commit
9e466635de
|
@ -19,6 +19,9 @@
|
|||
},
|
||||
{
|
||||
"url": "https://*"
|
||||
},
|
||||
{
|
||||
"url": "http://localhost:5000"
|
||||
}
|
||||
],
|
||||
"identifier": "http:default"
|
||||
|
|
|
@ -33,15 +33,12 @@ export const ServerStatus = () => {
|
|||
try {
|
||||
const response = await fetch(serverUrl + "/health");
|
||||
if (response.ok) {
|
||||
console.log("connected");
|
||||
setServerConnection("connected");
|
||||
} else {
|
||||
console.log("disconnected");
|
||||
await sleep(500);
|
||||
setServerConnection("disconnected");
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("disconnected", e);
|
||||
await sleep(500);
|
||||
setServerConnection("disconnected");
|
||||
}
|
||||
|
@ -60,13 +57,11 @@ export const ServerStatus = () => {
|
|||
useEffect(() => {
|
||||
// only start interval if server is connected
|
||||
if (serverConnection === "connected") {
|
||||
const intervalId = setInterval(checkServerConnection, 2000);
|
||||
console.log("Started server ping interval");
|
||||
const intervalId = setInterval(checkServerConnection, 5000);
|
||||
|
||||
// cleanup interval on disconnection or component unmount
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
console.log("Stopped server ping interval");
|
||||
};
|
||||
}
|
||||
}, [serverConnection, serverUrl]);
|
||||
|
@ -82,7 +77,7 @@ export const ServerStatus = () => {
|
|||
>
|
||||
{serverConnection === "connecting" && (
|
||||
<CircularProgress
|
||||
size='20px'
|
||||
size="20px"
|
||||
sx={{ mr: 1 }}
|
||||
/>
|
||||
)}
|
||||
|
@ -90,7 +85,7 @@ export const ServerStatus = () => {
|
|||
<Chip
|
||||
{...chipProps}
|
||||
onClick={clickEvent}
|
||||
size='small'
|
||||
size="small"
|
||||
/>
|
||||
<Popover
|
||||
anchorEl={anchorEl}
|
||||
|
@ -124,15 +119,15 @@ export const ServerStatus = () => {
|
|||
}}
|
||||
>
|
||||
<Stack
|
||||
alignItems='center'
|
||||
display='flex'
|
||||
direction='row'
|
||||
alignItems="center"
|
||||
display="flex"
|
||||
direction="row"
|
||||
spacing={1}
|
||||
>
|
||||
<ServerUrlInput />
|
||||
<Button
|
||||
type='submit'
|
||||
variant='outlined'
|
||||
type="submit"
|
||||
variant="outlined"
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
|
|
|
@ -9,7 +9,7 @@ export const SqlInjection = () => {
|
|||
const theme = useTheme();
|
||||
|
||||
// states
|
||||
const [subTabValue, setSubTabValue] = useState("style");
|
||||
const [subTabValue, setSubTabValue] = useState("register");
|
||||
|
||||
// logic for switching tabs
|
||||
const subTabChangeEvent = (newTabValue: string) => {
|
||||
|
|
|
@ -4,18 +4,21 @@ import { fetch } from "@tauri-apps/plugin-http";
|
|||
import { useAtom } from "jotai";
|
||||
import { useState } from "react";
|
||||
import { serverUrlAtom } from "../../../lib/jotai";
|
||||
import { sleep } from "../../../lib/utility";
|
||||
import { HeaderLogo } from "../../Generic/HeaderLogo";
|
||||
import { useNotification } from "../../../contexts/NotificationContext";
|
||||
|
||||
export const SqlInjectionRegister = () => {
|
||||
// contexts
|
||||
const { openNotification } = useNotification();
|
||||
|
||||
// atoms
|
||||
const [serverUrl, setServerUrl] = useAtom(serverUrlAtom);
|
||||
|
||||
// states
|
||||
const [emailValueRaw, setEmailValueRaw] = useState<string>("");
|
||||
const [errorMsg, setErrorMsg] = useState<string>("");
|
||||
const [passwordValueRaw, setPasswordValueRaw] = useState<string>("");
|
||||
const [rePasswordValueRaw, setRePasswordValueRaw] = useState<string>("");
|
||||
const [passwordErrorMsg, setPasswordErrorMsg] = useState<string>("");
|
||||
const [passwordStrength, setPasswordStrength] = useState(0);
|
||||
const [passwordStrengthColor, setPasswordStrengthColor] = useState<"primary" | "error" | "warning" | "success">(
|
||||
"primary",
|
||||
|
@ -86,16 +89,45 @@ export const SqlInjectionRegister = () => {
|
|||
};
|
||||
|
||||
const nextClickEvent = async () => {
|
||||
// make a request to the server
|
||||
setRegisterLoading(true);
|
||||
// remove trailing slash
|
||||
// reset the error messages
|
||||
setErrorMsg("");
|
||||
|
||||
// ensure that the server url does not end with a trailing slash
|
||||
setServerUrl(serverUrl.replace(/\/$/, ""));
|
||||
|
||||
// construct the request body
|
||||
const requestBody = {
|
||||
email: emailValueRaw,
|
||||
password: passwordValueRaw,
|
||||
rePassword: rePasswordValueRaw,
|
||||
};
|
||||
|
||||
// start loading indicator
|
||||
setRegisterLoading(true);
|
||||
|
||||
try {
|
||||
const response = await fetch(serverUrl + "/sql-register");
|
||||
console.log;
|
||||
// make request good
|
||||
const response = await fetch(serverUrl + "/register-sql", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
});
|
||||
|
||||
// check if registration was successful
|
||||
if (!response.ok) {
|
||||
const errorMessage = await response.text();
|
||||
console.log("Registration failed:", errorMessage);
|
||||
setErrorMsg(errorMessage);
|
||||
} else {
|
||||
openNotification("Registration successful");
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("failed", e);
|
||||
await sleep(500);
|
||||
// Log the error and handle failure
|
||||
console.log("Request failed", e);
|
||||
} finally {
|
||||
// Stop loading indicator regardless of success/failure
|
||||
setRegisterLoading(false);
|
||||
}
|
||||
};
|
||||
|
@ -133,6 +165,7 @@ export const SqlInjectionRegister = () => {
|
|||
}}
|
||||
>
|
||||
<TextField
|
||||
error={Boolean(errorMsg)}
|
||||
fullWidth
|
||||
id="email"
|
||||
label="Email"
|
||||
|
@ -144,9 +177,8 @@ export const SqlInjectionRegister = () => {
|
|||
variant="outlined"
|
||||
/>
|
||||
<TextField
|
||||
error={Boolean(passwordErrorMsg)}
|
||||
error={Boolean(errorMsg)}
|
||||
fullWidth
|
||||
helperText={Boolean(passwordErrorMsg) ? passwordErrorMsg : ""}
|
||||
id="password"
|
||||
label="Password"
|
||||
onChange={(e: { target: { value: string } }) => passwordInputEvent(e.target.value)}
|
||||
|
@ -157,9 +189,9 @@ export const SqlInjectionRegister = () => {
|
|||
variant="outlined"
|
||||
/>
|
||||
<TextField
|
||||
error={Boolean(passwordErrorMsg)}
|
||||
error={Boolean(errorMsg)}
|
||||
fullWidth
|
||||
helperText={Boolean(passwordErrorMsg) ? passwordErrorMsg : ""}
|
||||
helperText={Boolean(errorMsg) ? errorMsg : ""}
|
||||
id="re-password"
|
||||
label="Re-enter password"
|
||||
onChange={(e: { target: { value: string } }) => rePasswordInputEvent(e.target.value)}
|
||||
|
|
|
@ -17,7 +17,10 @@ export const Testing = () => {
|
|||
const close = () => setOpenState(false);
|
||||
|
||||
const testing = () => {
|
||||
fetch("https://ip.vomitblood.com/ping").then((response) => {
|
||||
fetch("http://localhost:5000/nuke-db").then((response) => {
|
||||
console.log(response);
|
||||
});
|
||||
fetch("http://localhost:5000/setup-demo-db").then((response) => {
|
||||
console.log(response);
|
||||
});
|
||||
};
|
||||
|
@ -53,14 +56,14 @@ export const Testing = () => {
|
|||
openButton={
|
||||
<IconButton
|
||||
onClick={() => setOpenState(true)}
|
||||
size='small'
|
||||
size="small"
|
||||
>
|
||||
<BugReportOutlined />
|
||||
</IconButton>
|
||||
}
|
||||
openState={openState}
|
||||
setMaximisedState={setMaximisedState}
|
||||
title='Testing'
|
||||
title="Testing"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -10,3 +10,5 @@ services:
|
|||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
volumes:
|
||||
postgres_data:
|
||||
|
|
|
@ -7,7 +7,7 @@ require (
|
|||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.1 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
golang.org/x/crypto v0.27.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
)
|
||||
|
|
|
@ -13,9 +13,15 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
|||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -21,7 +21,6 @@ const (
|
|||
)
|
||||
|
||||
var DbPool *pgxpool.Pool
|
||||
var allowedUsernames map[string]bool
|
||||
|
||||
// initialize connection to db
|
||||
func ConnectToDb() (*pgxpool.Pool, error) {
|
||||
|
@ -79,19 +78,19 @@ func SetupDemoDb(w http.ResponseWriter, r *http.Request) {
|
|||
// create table and insert demo data
|
||||
createTableSQL := `
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
username VARCHAR(50) UNIQUE NOT NULL,
|
||||
email VARCHAR(100) NOT NULL,
|
||||
password VARCHAR(100) NOT NULL
|
||||
id SERIAL PRIMARY KEY,
|
||||
email VARCHAR(100) NOT NULL,
|
||||
password VARCHAR(100) NOT NULL,
|
||||
role VARCHAR(50) DEFAULT 'user'
|
||||
);`
|
||||
|
||||
// also avoid duplicate entries
|
||||
// avoid duplicate entries and specify roles
|
||||
insertDataSQL := `
|
||||
INSERT INTO users (username, email, password) VALUES
|
||||
('alice', 'alice@example.com', 'asdfalicepassword'),
|
||||
('bob', 'bob@example.com', 'asdfbobpassword'),
|
||||
('charlie', 'charlie@example.com', 'asdfcharliepassword')
|
||||
ON CONFLICT (username) DO NOTHING;`
|
||||
INSERT INTO users (email, password, role) VALUES
|
||||
('alice@example.com', 'asdfalicepassword', 'user'),
|
||||
('bob@example.com', 'asdfbobpassword', 'user'),
|
||||
('charlie@example.com', 'asdfcharliepassword', 'admin')
|
||||
`
|
||||
|
||||
// execute create table
|
||||
_, err := DbPool.Exec(context.Background(), createTableSQL)
|
||||
|
|
|
@ -24,6 +24,7 @@ func ServeApi() {
|
|||
http.HandleFunc("/execute-sql", sql_injection.ExecuteSql)
|
||||
http.HandleFunc("/login-sql", sql_injection.LoginSql)
|
||||
http.HandleFunc("/secure-execute-sql", sql_injection.SecureExecuteSql)
|
||||
http.HandleFunc("/register-sql", sql_injection.RegisterSql)
|
||||
http.HandleFunc("/secure-login-sql", sql_injection.SecureLoginSql)
|
||||
http.HandleFunc("/secure-get-user", sql_injection.SecureGetUser)
|
||||
log.Println("Server is running on http://localhost:5000")
|
||||
|
|
|
@ -7,9 +7,11 @@ import (
|
|||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Vomitblood/cspj-application/server/internal/db"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// unsecure version
|
||||
|
@ -147,6 +149,72 @@ func SecureExecuteSql(w http.ResponseWriter, r *http.Request) {
|
|||
w.Write(jsonResp)
|
||||
}
|
||||
|
||||
// register endpoint
|
||||
func RegisterSql(w http.ResponseWriter, r *http.Request) {
|
||||
// read the request body
|
||||
var credentials struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
RePassword string `json:"rePassword"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&credentials); err != nil {
|
||||
http.Error(w, "Invalid request format", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
// check if the email is an email using regex, if not reject
|
||||
emailRegex := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
|
||||
re := regexp.MustCompile(emailRegex)
|
||||
if !re.MatchString(credentials.Email) {
|
||||
http.Error(w, "Invalid email format", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// check if the password matches, if not reject
|
||||
if credentials.Password != credentials.RePassword {
|
||||
http.Error(w, "Passwords do not match", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// get the number of emails that matches
|
||||
var existingUserCount int
|
||||
emailCheckSQL := `SELECT COUNT(*) FROM users WHERE email = $1`
|
||||
err := db.DbPool.QueryRow(context.Background(), emailCheckSQL, credentials.Email).Scan(&existingUserCount)
|
||||
if err != nil {
|
||||
http.Error(w, "Error checking email in the database", http.StatusInternalServerError)
|
||||
log.Printf("Error checking email: %v", err)
|
||||
return
|
||||
}
|
||||
// if there is more than 0 matches, that means email already exists, reject
|
||||
if existingUserCount > 0 {
|
||||
http.Error(w, "Email already exists", http.StatusConflict)
|
||||
return
|
||||
}
|
||||
|
||||
// hash the password
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(credentials.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
http.Error(w, "Error hashing password", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// over here the validations has passed, so insert into the db
|
||||
insertSQL := `INSERT INTO users (email, password, role) VALUES ($1, $2, $3)`
|
||||
_, err = db.DbPool.Exec(context.Background(), insertSQL, credentials.Email, hashedPassword, "user")
|
||||
if err != nil {
|
||||
http.Error(w, "Error inserting user into the database", http.StatusInternalServerError)
|
||||
log.Printf("Error inserting user: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// send back status ok
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("User registered successfully"))
|
||||
log.Println("User registered successfully:", credentials.Email)
|
||||
}
|
||||
|
||||
// secure login
|
||||
func SecureLoginSql(w http.ResponseWriter, r *http.Request) {
|
||||
var credentials struct {
|
||||
|
|
Loading…
Reference in a new issue