Skip to content

Instantly share code, notes, and snippets.

@lucky-rydar
Created October 23, 2023 12:49
Show Gist options
  • Save lucky-rydar/f0502d90a51246902039f73d6b27bc11 to your computer and use it in GitHub Desktop.
Save lucky-rydar/f0502d90a51246902039f73d6b27bc11 to your computer and use it in GitHub Desktop.
security lab 5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Login</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<main id="main-holder">
<a href="/logout" id="logout">Logout</a>
<h1 id="login-header">Login</h1>
<div id="login-error-msg-holder">
<p id="login-error-msg">
Invalid username
<span id="error-msg-second-line">and/or password</span>
</p>
</div>
<form id="login-form" action="/api/login" method="post">
<input
type="text"
name="login"
id="username-field"
class="login-form-field"
placeholder="Username"
/>
<input
type="password"
name="password"
id="password-field"
class="login-form-field"
placeholder="Password"
/>
<input type="submit" value="Login" id="login-form-submit" />
</form>
<div class="private-area">
<a href="/api/private" class="private-link">Private Area</a>
<p class="private-text"></p>
</div>
</main>
</body>
<style>
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
font-family: Arial, Helvetica, sans-serif;
display: grid;
justify-items: center;
align-items: center;
background-color: #3a3a3a;
}
#logout {
opacity: 0;
}
#main-holder {
width: 50%;
height: 70%;
display: grid;
justify-items: center;
align-items: center;
background-color: white;
border-radius: 7px;
box-shadow: 0px 0px 5px 2px black;
}
#login-error-msg-holder {
width: 100%;
height: 100%;
display: grid;
justify-items: center;
align-items: center;
}
#login-error-msg {
width: 23%;
text-align: center;
margin: 0;
padding: 5px;
font-size: 12px;
font-weight: bold;
color: #8a0000;
border: 1px solid #8a0000;
background-color: #e58f8f;
opacity: 0;
}
#error-msg-second-line {
display: block;
}
#login-form {
align-self: flex-start;
display: grid;
justify-items: center;
align-items: center;
}
.login-form-field::placeholder {
color: #3a3a3a;
}
.login-form-field {
border: none;
border-bottom: 1px solid #3a3a3a;
margin-bottom: 10px;
border-radius: 3px;
outline: none;
padding: 0px 0px 5px 5px;
}
#login-form-submit {
width: 100%;
padding: 7px;
border: none;
border-radius: 5px;
color: white;
font-weight: bold;
background-color: #3a3a3a;
cursor: pointer;
outline: none;
}
.private-link{
opacity: 0;
}
</style>
<script>
const token = sessionStorage.getItem('token');
if (token) {
axios
.get('/', {
headers: {
Authorization: token,
},
})
.then((response) => {
const mainHolder = document.getElementById('main-holder');
const loginHeader = document.getElementById('login-header');
loginForm.remove();
loginErrorMsg.remove();
loginHeader.remove();
mainHolder.append('Hello, you successfully signed in');
logoutLink.style.opacity = 1;
document.querySelector('.private-link').style.opacity = '1';
});
}
const loginForm = document.getElementById('login-form');
const loginButton = document.getElementById('login-form-submit');
const loginErrorMsg = document.getElementById('login-error-msg');
const logoutLink = document.getElementById('logout');
logoutLink.addEventListener('click', (e) => {
e.preventDefault();
sessionStorage.removeItem('token');
location.reload();
});
loginButton.addEventListener('click', (e) => {
e.preventDefault();
const login = loginForm.login.value;
const password = loginForm.password.value;
axios({
method: 'post',
url: '/api/login',
data: {
login,
password,
},
})
.then((response) => {
sessionStorage.setItem(
'token',
JSON.stringify(response.data)
);
location.reload();
})
.catch((response) => {
loginErrorMsg.style.opacity = 1;
});
});
const privateLink = document.querySelector('.private-link');
privateLink.addEventListener('click', (e) => {
e.preventDefault();
console.log(token)
const parsed = JSON.parse(token);
const raw_token = parsed.token;
axios.get('/api/private', {
headers: {
Authorization: `Bearer ${raw_token}`
}
})
.then((res) => {
console.log(res.data);
const privateText = document.querySelector('.private-text');
privateText.innerHTML = JSON.stringify(res.data.message);
})
.catch((err) => {
console.log(err);
})
})
</script>
</html>
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const axios = require('axios');
const { config } = require('dotenv');
const { auth } = require('express-oauth2-jwt-bearer');
config();
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const SESSION_KEY = 'Authorization';
const verifyJwt = auth({
audience: process.env.AUDIENCE,
issuerBaseURL: `https://${process.env.DOMAIN}/`,
});
const createUser = async (res, email, given_name, family_name, name, nickname, password) => {
try {
const createUserResponse = await axios.post(`https://${process.env.DOMAIN}/api/v2/users`, {
email,
given_name,
family_name,
name,
nickname,
connection: 'Username-Password-Authentication',
password,
}, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${process.env.ACCESS_TOKEN}`,
},
});
console.log('Created user');
res.status(createUserResponse.status).send();
} catch (error) {
console.error('createUserOptions:', error);
res.status(500).send(error.message);
}
};
app.use(async (req, res, next) => {
const fulltoken = req.get(SESSION_KEY);
if (fulltoken) {
try {
JSON.parse(fulltoken);
}
catch (e) {
console.log("Token is not JSON");
req.token = fulltoken;
next();
return;
}
const token = JSON.parse(fulltoken);
const expiresDate = new Date(token.expiresDate);
expiresDate.setHours(expiresDate.getHours() - 1); // 1 hour
const currentDate = new Date();
console.log('HAVE A TOKEN');
console.log('expiresDate:', expiresDate);
console.log('currentDate:', currentDate);
console.log('Is valid: ', currentDate < expiresDate);
if (expiresDate < currentDate) {
console.log('USER_ACCESS_TOKEN', process.env.USER_ACCESS_TOKEN);
console.log('USER_REFRESH_TOKEN', process.env.USER_REFRESH_TOKEN);
try {
const refreshTokenResponse = await axios.post(`https://${process.env.DOMAIN}/oauth/token`, {
grant_type: 'refresh_token',
audience: process.env.AUDIENCE,
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
refresh_token: process.env.USER_REFRESH_TOKEN,
}, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Bearer ${process.env.USER_ACCESS_TOKEN}`,
},
});
const info = refreshTokenResponse.data;
process.env.USER_ACCESS_TOKEN = info.access_token;
console.log('Refreshed Token:', info.access_token);
const now = new Date();
const newExpiresDate = new Date(now.getTime() + info.expires_in * 1000);
req.token = JSON.stringify({
token: info.access_token,
expiresDate: newExpiresDate,
});
} catch (error) {
console.error(error);
}
} else {
req.token = token;
}
}
next();
});
app.get('/', (req, res) => {
if (req.username) {
return res.json({
username: req.username,
logout: 'http://localhost:3000/logout',
});
}
res.sendFile(path.join(__dirname, '/index.html'));
});
app.get('/register', (req, res) => {
if (req.username) {
return res.json({
username: req.username,
logout: 'http://localhost:3000/logout',
});
}
res.sendFile(path.join(__dirname, '/register.html'));
});
app.get('/logout', (req, res) => {
res.redirect('/');
});
app.post('/api/login', async (req, res) => {
const { login, password } = req.body;
try {
const getTokensResponse = await axios.post(`https://${process.env.DOMAIN}/oauth/token`, {
audience: process.env.AUDIENCE,
grant_type: 'password',
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
username: login,
password: password,
scope: 'offline_access',
}, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
const info = getTokensResponse.data;
process.env.USER_ACCESS_TOKEN = info.access_token;
process.env.USER_REFRESH_TOKEN = info.refresh_token;
console.log('/api/login:', info);
const now = new Date();
const expiresDate = new Date(now.getTime() + info.expires_in * 1000);
res.json({ token: info.access_token, expiresDate });
} catch (error) {
res.status(error.response?.status || 500).send(error.message);
}
});
app.get('/api/private', verifyJwt, function(req, res) {
res.json({
message: 'Hello from a private endpoint! You need to be authenticated to see this.'
});
});
app.post('/api/register', (req, res) => {
console.log(req.body);
createUser(
res,
req.body.email,
req.body.givenname,
req.body.familyname,
req.body.nickname,
req.body.name,
req.body.password
);
return;
});
const getTokenRequest = {
method: 'POST',
url: `https://${process.env.DOMAIN}/oauth/token`,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: {
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
audience: process.env.AUDIENCE,
grant_type: 'client_credentials',
},
};
axios(getTokenRequest)
.then(response => {
const info = response.data;
process.env.ACCESS_TOKEN = info.access_token;
console.log('body: ', info);
})
.catch(error => {
console.error(error);
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Register</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<main id="main-holder">
<h1 id="register-header">Register</h1>
<div id="register-error-msg-holder">
<p id="register-error-msg">
Please check the data
<span id="error-msg-second-line">maybe this email is used</span>
</p>
</div>
<form id="register-form" action="/api/register" method="post">
<input
type="text"
required
name="email"
id="email-field"
class="register-form-field"
placeholder="Email"
/>
<input
type="text"
required
name="givenname"
id="givenname-field"
class="register-form-field"
placeholder="Given Name"
/>
<input
type="text"
required
name="familyname"
id="familyname-field"
class="register-form-field"
placeholder="Family Name"
/>
<input
type="text"
required
name="name"
id="name-field"
class="register-form-field"
placeholder="Name"
/>
<input
type="text"
required
name="nickname"
id="nickname-field"
class="register-form-field"
placeholder="Nickname"
/>
<input
type="password"
required
name="password"
id="password-field"
class="register-form-field"
placeholder="Password"
/>
<input
type="submit"
value="Create an account"
id="register-form-submit"
/>
</form>
</main>
</body>
<style>
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
font-family: Arial, Helvetica, sans-serif;
display: grid;
justify-items: center;
align-items: center;
background-color: #3a3a3a;
}
#logout {
opacity: 0;
}
#main-holder {
width: 50%;
height: 70%;
display: grid;
justify-items: center;
align-items: center;
background-color: white;
border-radius: 7px;
box-shadow: 0px 0px 5px 2px black;
}
#register-error-msg-holder {
width: 100%;
height: 100%;
display: grid;
justify-items: center;
align-items: center;
}
#register-error-msg {
width: 23%;
text-align: center;
margin: 0;
padding: 5px;
font-size: 12px;
font-weight: bold;
color: #8a0000;
border: 1px solid #8a0000;
background-color: #e58f8f;
opacity: 0;
}
#error-msg-second-line {
display: block;
}
#register-form {
align-self: flex-start;
display: grid;
justify-items: center;
align-items: center;
}
.register-form-field::placeholder {
color: #3a3a3a;
}
.register-form-field {
border: none;
border-bottom: 1px solid #3a3a3a;
margin-bottom: 10px;
border-radius: 3px;
outline: none;
padding: 0px 0px 5px 5px;
}
#register-form-submit {
width: 100%;
padding: 7px;
border: none;
border-radius: 5px;
color: white;
font-weight: bold;
background-color: #3a3a3a;
cursor: pointer;
outline: none;
}
</style>
<script>
const token = sessionStorage.getItem('token');
if (token) {
window.location.href = '/';
}
const registerForm = document.getElementById('register-form');
const registerButton = document.getElementById('register-form-submit');
const registerErrorMsg = document.getElementById('register-error-msg');
registerButton.addEventListener('click', (e) => {
e.preventDefault();
const email = registerForm.email.value;
const givenname = registerForm.givenname.value;
const familyname = registerForm.familyname.value;
const nickname = registerForm.nickname.value;
const name = registerForm.name.value;
const password = registerForm.password.value;
axios({
method: 'post',
url: '/api/register',
data: {
email,
givenname,
familyname,
nickname,
name,
password,
},
})
.then((response) => {
const status = response.status;
if (status >= 200 && status < 300) {
window.location.href = '/';
}
})
.catch((response) => {
registerErrorMsg.style.opacity = 1;
registerErrorMsg.innerHTML += response.request.status;
});
});
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment