FastAuth/frontend/src/App.vue

240 lines
5.3 KiB
Vue

<script setup>
import CreateSecret from "./components/CreateSecret.vue";
import HomePage from "./components/HomePage.vue";
import ImportSecrets from "./components/ImportSecrets.vue";
import ListSecrets from "./components/ListSecrets.vue";
</script>
<template>
<div>
<div id="header" class="header">
<span class="logo">FastAuth</span>
<div class="header-buttons" v-if="loggedin">
<button class="header-button" title="Refresh secrets" @click="refresh">
<img src="./assets/refresh-icon.png" class="button-icon" />
</button>
<button class="header-button" title="logout" @click="logout">
<img src="./assets/logout-icon.png" class="button-icon" />
</button>
</div>
</div>
<el-dialog
v-model="creationDialog"
title="Add a new TOTP secret"
destroy-on-close
width="80vw"
>
<CreateSecret @close="secretSaved" />
</el-dialog>
<el-dialog
v-model="editDialog"
title="Edit TOTP secret"
destroy-on-close
width="80vw"
>
<CreateSecret :editSecret="editingSecret" @close="secretSaved" />
</el-dialog>
<el-dialog
v-model="importDialog"
title="Import TOTP secrets"
destroy-on-close
width="80vw"
>
<ImportSecrets @close="secretsImported" />
</el-dialog>
<div class="container">
<div class="timer" v-if="loggedin" :style="{ width: timerWidth + '%' }"></div>
<HomePage
msg="You did it!"
@loggedin="
loggedin = true;
showSecrets = true;
"
v-if="!loggedin"
/>
<!-- <el-button @click="showSecrets = true" v-if="loggedin"> Show secrets </el-button>
<el-button @click="showSecrets = false" v-if="showSecrets && loggedin">
Hide secrets
</el-button> -->
<ListSecrets :key="listUpdated" v-if="showSecrets && loggedin" @edit="editSecret" />
</div>
<button class="create-floating" @click="creationDialog = true">+</button>
<button class="create-floating mb50" @click="importDialog = true">i</button>
</div>
</template>
<script>
export default {
components: { ImportSecrets },
data() {
return {
loggedin: false,
showSecrets: false,
creationDialog: false,
listUpdated: 1,
apiBaseUrl: "http://localhost:8000",
editDialog: false,
editingSecret: {},
importDialog: false,
timerWidth: 0,
};
},
methods: {
logout() {
sessionStorage.removeItem("token");
this.loggedin = false;
},
secretSaved() {
this.creationDialog = false;
this.editDialog = false;
this.listUpdated += 1;
},
secretsImported() {
this.importDialog = false;
this.listUpdated += 1;
},
async validateToken() {
const url = `${this.apiBaseUrl}/validate-token`;
const token = sessionStorage.getItem("token");
const requestOptions = {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
};
const response = await fetch(url, requestOptions)
.then((response) => response.json())
.catch((err) => {
console.log(err);
return false;
});
if (!response) {
return false;
}
if ("message" in response) {
if (response["message"] === "authenticated") {
console.log("token validated");
return true;
}
}
return false;
},
editSecret(secret) {
this.editingSecret = secret;
// console.log(this.editingSecret);
this.editDialog = true;
},
refresh() {
this.listUpdated += 1;
},
startTimer() {
// console.log("start timer called");
this.interval = setInterval(() => {
const now = new Date();
const seconds = now.getSeconds();
const remainingTime = (seconds > 30 ? 60 : 30) - seconds;
this.timerWidth = (remainingTime / 30) * 100;
}, 1000);
},
},
async mounted() {
if ("token" in sessionStorage) {
const tokenValid = await this.validateToken();
if (tokenValid) {
this.loggedin = true;
this.showSecrets = true;
}
this.startTimer();
}
},
};
</script>
<style scoped>
.container {
margin-top: 6vh;
}
.logoutBtn {
/* position: relative; */
margin-right: 0;
margin-left: auto;
}
.el-page-header__back {
display: none !important;
}
.header {
width: 100vw;
height: 48px;
position: fixed;
left: 0;
top: 0;
background-color: rgb(170, 247, 247);
display: flex;
align-items: center;
padding: 0 12px 0 12px;
justify-content: space-between;
box-shadow: 2px 0px 8px #aaa;
z-index: 999;
}
.logo {
font-size: 1.3rem;
font-weight: 700;
margin-left: 2vw;
}
.timer {
position: fixed;
bottom: 4px;
height: 0.3rem;
background-color: green;
}
.create-floating {
position: fixed;
bottom: 4vh;
right: 4vw;
height: 40px;
width: 40px;
border: none;
border-radius: 20px;
box-shadow: 4px 4px 6px #999;
background-color: teal;
color: white;
font-size: 1.6rem;
cursor: pointer;
}
.button-icon {
width: 24px;
margin-top: 8px;
height: 24px;
opacity: 0.6;
}
.header-button {
border: none;
background: none;
}
.mb50 {
margin-bottom: 50px;
}
</style>