wg-portal/frontend/src/components/PeerViewModal.vue

203 lines
6.9 KiB
Vue
Raw Normal View History

2023-02-12 23:13:04 +01:00
<script setup>
import Modal from "./Modal.vue";
import {peerStore} from "@/stores/peers";
import {interfaceStore} from "@/stores/interfaces";
2023-06-24 01:35:25 +02:00
import {computed, ref, watch} from "vue";
import {useI18n} from "vue-i18n";
2023-07-18 16:05:06 +02:00
import {freshInterface, freshPeer, freshStats} from '@/helpers/models';
2023-06-24 01:35:25 +02:00
import Prism from "vue-prism-component";
2023-07-07 21:24:02 +02:00
import {notify} from "@kyvg/vue3-notification";
2023-07-21 15:13:00 +02:00
import {settingsStore} from "@/stores/settings";
2023-06-24 01:35:25 +02:00
const { t } = useI18n()
2023-02-12 23:13:04 +01:00
2023-07-21 15:13:00 +02:00
const settings = settingsStore()
2023-02-12 23:13:04 +01:00
const peers = peerStore()
const interfaces = interfaceStore()
const props = defineProps({
peerId: String,
visible: Boolean,
})
const emit = defineEmits(['close'])
function close() {
emit('close')
}
2023-06-24 01:35:25 +02:00
const configString = ref("")
2023-02-12 23:13:04 +01:00
const selectedPeer = computed(() => {
2023-06-24 01:35:25 +02:00
let p = peers.Find(props.peerId)
if (!p) {
p = freshPeer() // dummy peer to avoid 'undefined' exceptions
}
return p
2023-02-12 23:13:04 +01:00
})
2023-07-18 16:05:06 +02:00
const selectedStats = computed(() => {
let s = peers.Statistics(props.peerId)
if (!s) {
s = freshStats() // dummy peer to avoid 'undefined' exceptions
}
return s
})
2023-02-12 23:13:04 +01:00
const selectedInterface = computed(() => {
let i = interfaces.GetSelected;
if (!i) {
2023-06-24 01:35:25 +02:00
i = freshInterface() // dummy interface to avoid 'undefined' exceptions
2023-02-12 23:13:04 +01:00
}
return i
})
const title = computed(() => {
2023-06-24 01:35:25 +02:00
if (!props.visible) {
return "" // otherwise interfaces.GetSelected will die...
}
if (selectedInterface.value.Mode === "server") {
return t("interfaces.peer.view") + ": " + selectedPeer.value.DisplayName
} else {
return t("interfaces.endpoint.view") + ": " + selectedPeer.value.DisplayName
2023-02-12 23:13:04 +01:00
}
})
2023-06-24 01:35:25 +02:00
watch(() => props.visible, async (newValue, oldValue) => {
if (oldValue === false && newValue === true) { // if modal is shown
console.log(selectedInterface.value)
console.log(selectedPeer.value)
await peers.LoadPeerConfig(selectedPeer.value.Identifier)
configString.value = peers.configuration
}
}
)
2023-07-04 22:55:11 +02:00
function download() {
// credit: https://www.bitdegree.org/learn/javascript-download
let filename = 'WireGuard-Tunnel.conf'
if (selectedPeer.value.DisplayName) {
filename = selectedPeer.value.DisplayName
.replace(/ /g,"_")
.replace(/[^a-zA-Z0-9-_]/g,"")
.substring(0, 16)
+ ".conf"
}
let text = configString.value
let element = document.createElement('a')
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
}
2023-07-07 21:24:02 +02:00
function email() {
2023-07-21 15:13:00 +02:00
peers.MailPeerConfig(settings.Setting("MailLinkOnly"), [selectedPeer.value.Identifier]).catch(e => {
2023-07-07 21:24:02 +02:00
notify({
2023-07-21 15:13:00 +02:00
title: "Failed to send mail with peer configuration!",
text: e.toString(),
2023-07-07 21:24:02 +02:00
type: 'error',
})
})
}
2023-02-12 23:13:04 +01:00
</script>
<template>
<Modal :title="title" :visible="visible" @close="close">
<template #default>
2023-07-18 16:05:06 +02:00
<div class="accordion" id="peerInformation">
2023-02-12 23:13:04 +01:00
<div class="accordion-item">
<h2 class="accordion-header">
2023-07-18 16:05:06 +02:00
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseDetails" aria-expanded="true" aria-controls="collapseDetails">
2023-02-12 23:13:04 +01:00
Peer Information
</button>
</h2>
2023-07-18 16:05:06 +02:00
<div id="collapseDetails" class="accordion-collapse collapse show" aria-labelledby="headingDetails" data-bs-parent="#peerInformation" style="">
2023-02-12 23:13:04 +01:00
<div class="accordion-body">
<div class="row">
<div class="col-md-8">
<h4>Details</h4>
<ul>
2023-06-24 01:35:25 +02:00
<li>Identifier: {{ selectedPeer.PublicKey }}</li>
<li>IP Addresses: <span v-for="ip in selectedPeer.Addresses" :key="ip" class="badge rounded-pill bg-light">{{ ip }}</span></li>
<li>Linked User: {{ selectedPeer.UserIdentifier }}</li>
<li v-if="selectedPeer.Notes">Notes: {{ selectedPeer.Notes }}</li>
<li v-if="selectedPeer.ExpiresAt">Expires At: {{ selectedPeer.ExpiresAt }}</li>
<li v-if="selectedPeer.Disabled">Disabled Reason: {{ selectedPeer.DisabledReason }}</li>
2023-02-12 23:13:04 +01:00
</ul>
</div>
<div class="col-md-4">
2023-06-24 01:35:25 +02:00
<img class="config-qr-img" :src="peers.ConfigQrUrl(props.peerId)" loading="lazy" alt="Configuration QR Code">
2023-02-12 23:13:04 +01:00
</div>
</div>
</div>
</div>
</div>
2023-07-18 16:05:06 +02:00
<div class="accordion-item">
<h2 class="accordion-header" id="headingStatus">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStatus" aria-expanded="false" aria-controls="collapseStatus">
Current Status
</button>
</h2>
<div id="collapseStatus" class="accordion-collapse collapse" aria-labelledby="headingStatus" data-bs-parent="#peerInformation" style="">
<div class="accordion-body">
<div class="row">
<div class="col-md-12">
<h4>Traffic</h4>
<p><i class="fas fa-long-arrow-alt-down"></i> {{ selectedStats.BytesReceived }} Bytes / <i class="fas fa-long-arrow-alt-up"></i> {{ selectedStats.BytesTransmitted }} Bytes</p>
<h4>Connection Stats</h4>
<ul>
<li>Pingable: {{ selectedStats.IsPingable }}</li>
<li>Last Handshake: {{ selectedStats.LastHandshake }}</li>
<li>Connected Since: {{ selectedStats.LastSessionStart }}</li>
<li>Endpoint: {{ selectedStats.EndpointAddress }}</li>
</ul>
</div>
</div>
</div>
</div>
</div>
2023-02-12 23:13:04 +01:00
<div v-if="selectedInterface.Mode==='server'" class="accordion-item">
2023-07-18 16:05:06 +02:00
<h2 class="accordion-header" id="headingConfig">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseConfig" aria-expanded="false" aria-controls="collapseConfig">
2023-02-12 23:13:04 +01:00
Peer Configuration
</button>
</h2>
2023-07-18 16:05:06 +02:00
<div id="collapseConfig" class="accordion-collapse collapse" aria-labelledby="headingConfig" data-bs-parent="#peerInformation" style="">
2023-02-12 23:13:04 +01:00
<div class="accordion-body">
2023-06-24 01:35:25 +02:00
<Prism language="ini" :code="configString"></Prism>
2023-02-12 23:13:04 +01:00
</div>
</div>
</div>
</div>
</template>
<template #footer>
<div class="flex-fill text-start">
2023-07-04 22:55:11 +02:00
<button @click.prevent="download" type="button" class="btn btn-primary me-1">Download</button>
2023-07-07 21:24:02 +02:00
<button @click.prevent="email" type="button" class="btn btn-primary me-1">Email</button>
2023-02-12 23:13:04 +01:00
</div>
<button @click.prevent="close" type="button" class="btn btn-secondary">Close</button>
</template>
</Modal>
</template>
<style>
.config-qr-img {
max-width: 100%;
}
</style>