Created
October 23, 2023 12:49
-
-
Save lucky-rydar/f0502d90a51246902039f73d6b27bc11 to your computer and use it in GitHub Desktop.
security lab 5
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}`); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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