Import secret feature is now working
This commit is contained in:
parent
1af66916a9
commit
6a1429614b
@ -1,6 +1,7 @@
|
||||
<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>
|
||||
|
||||
@ -26,6 +27,10 @@ import ListSecrets from "./components/ListSecrets.vue";
|
||||
<CreateSecret :editSecret="editingSecret" @close="secretSaved" />
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="importDialog" title="Import TOTP secrets" width="80vw">
|
||||
<ImportSecrets />
|
||||
</el-dialog>
|
||||
|
||||
<div class="container">
|
||||
<div class="timer" v-if="loggedin" :style="{ width: timerWidth + '%' }"></div>
|
||||
<HomePage
|
||||
@ -43,11 +48,13 @@ import ListSecrets from "./components/ListSecrets.vue";
|
||||
<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,
|
||||
@ -57,6 +64,7 @@ export default {
|
||||
apiBaseUrl: "http://localhost:8000",
|
||||
editDialog: false,
|
||||
editingSecret: {},
|
||||
importDialog: false,
|
||||
timerWidth: 0,
|
||||
};
|
||||
},
|
||||
@ -204,4 +212,8 @@ export default {
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.mb50 {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
</style>
|
||||
|
@ -20,7 +20,7 @@ export default {
|
||||
message: "Hello world!",
|
||||
apiBaseUrl: "http://localhost:8000",
|
||||
form: {
|
||||
username: "gourav",
|
||||
username: "gouravkr",
|
||||
password: "hello123",
|
||||
},
|
||||
};
|
||||
|
141
frontend/src/components/ImportSecrets.vue
Normal file
141
frontend/src/components/ImportSecrets.vue
Normal file
@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<div class="import-container">
|
||||
<!-- <h3>Select a File to Read</h3> -->
|
||||
<input type="file" id="fileInput" @change="readFile" /> <br />
|
||||
|
||||
<button @click="parseTotpUri">Parse tokens</button>
|
||||
<button @click="saveImportedSecrets">Save tokens</button>
|
||||
<div class="token-list">
|
||||
<span v-for="token in parsedTokens" :key="token.issuer">
|
||||
<p v-for="(value, name) in token" :key="name">{{ name }}: {{ value }}</p>
|
||||
<br />
|
||||
</span>
|
||||
<!-- <span>{{ parsedTokens }}</span> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
apiBaseUrl: "http://localhost:8000",
|
||||
message: "hello",
|
||||
file: null,
|
||||
fileContent: null,
|
||||
allTokens: [],
|
||||
parsedTokens: [],
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
parseFile() {
|
||||
var authArr = this.fileContent.split("\r\n");
|
||||
authArr.forEach((ele) => {
|
||||
if (ele.length > 80) {
|
||||
this.allTokens.push(decodeURIComponent(ele));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
readFile(e) {
|
||||
const file = e.target.files[0]; // Get the selected file
|
||||
if (file) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
this.fileContent = reader.result;
|
||||
};
|
||||
reader.readAsText(file);
|
||||
} else {
|
||||
document.getElementById("fileContent").textContent = "No file selected";
|
||||
}
|
||||
},
|
||||
|
||||
parseTotpUri() {
|
||||
this.parseFile();
|
||||
this.allTokens.forEach((token) => {
|
||||
const url = new URL(token);
|
||||
const scheme = url.protocol.slice(0, -1);
|
||||
var label = decodeURIComponent(url.pathname.slice(1)); // Remove the leading '/'
|
||||
const type = label.slice(1, -1).split("/")[0];
|
||||
label = label.slice(6);
|
||||
let accountName, issuerFromLabel;
|
||||
const labelParts = label.split(":");
|
||||
if (labelParts.length === 2) {
|
||||
issuerFromLabel = labelParts[0];
|
||||
accountName = labelParts[1];
|
||||
} else {
|
||||
accountName = label;
|
||||
}
|
||||
|
||||
const params = {};
|
||||
url.searchParams.forEach((value, key) => {
|
||||
params[key] = value;
|
||||
});
|
||||
|
||||
console.log(params);
|
||||
|
||||
const secret = params.secret;
|
||||
const issuer = params.issuer || issuerFromLabel;
|
||||
const algorithm = params.algorithm || "SHA1";
|
||||
const digits = params.digits || "6";
|
||||
const period = params.period || "30";
|
||||
const counter = params.counter;
|
||||
|
||||
const parts = {
|
||||
scheme,
|
||||
type,
|
||||
label,
|
||||
accountName,
|
||||
issuer,
|
||||
secret,
|
||||
algorithm,
|
||||
digits,
|
||||
period,
|
||||
counter,
|
||||
};
|
||||
|
||||
this.parsedTokens.push(parts);
|
||||
});
|
||||
},
|
||||
|
||||
async createSecret(formData) {
|
||||
const url = `${this.apiBaseUrl}/secret`;
|
||||
const token = sessionStorage.getItem("token");
|
||||
const bodyData = { data: btoa(JSON.stringify(formData)) };
|
||||
const requestOptions = {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify(bodyData),
|
||||
};
|
||||
console.log("this request sent\n", requestOptions);
|
||||
await fetch(url, requestOptions)
|
||||
.then((response) => response.json())
|
||||
.then((data) => console.log(data));
|
||||
},
|
||||
|
||||
async saveImportedSecrets() {
|
||||
for (var i = 0; i < this.parsedTokens.length; i++) {
|
||||
await this.createSecret(this.parsedTokens[i]);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.import-container {
|
||||
/* max-height: 60vh; */
|
||||
overflow: hidden;
|
||||
margin-top: 1vh;
|
||||
}
|
||||
|
||||
.token-list {
|
||||
height: 60vh;
|
||||
margin-top: 10px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user