125 lines
4.8 KiB
Vue
125 lines
4.8 KiB
Vue
<script setup>
|
|
import { ref } from 'vue';
|
|
import { TabPanel} from '@headlessui/vue'
|
|
import * as secp from '@noble/secp256k1'
|
|
import { KeyIcon, ArrowPathIcon, ClipboardDocumentIcon } from '@heroicons/vue/24/solid'
|
|
|
|
import Card from '@/components/cards/Card.vue';
|
|
import CardHeader from '@/components/cards/CardHeader.vue';
|
|
import CardTitle from '@/components/cards/CardTitle.vue';
|
|
import CardDescription from '@/components/cards/CardDescription.vue';
|
|
import CardContent from '@/components/cards/CardContent.vue';
|
|
import Label from '@/components/labels/Label.vue';
|
|
import InputText from '@/components/inputs/InputText.vue';
|
|
import Button from '@/components/buttons/Button.vue';
|
|
import ToogleSwitch from '@/components/buttons/ToogleSwitch.vue';
|
|
|
|
const privateKeyInput = ref("")
|
|
const privateKeyB64 = ref("")
|
|
const publicKeyB64 = ref("")
|
|
const isTextEnabled = ref(true)
|
|
|
|
async function generate() {
|
|
var array = null
|
|
if (isTextEnabled.value){
|
|
const encoder = new TextEncoder();
|
|
const hashBuffer = await crypto.subtle.digest('SHA-256', encoder.encode(privateKeyInput.value));
|
|
array = new Uint8Array(hashBuffer);
|
|
|
|
privateKeyB64.value = btoa(String.fromCharCode(...array))
|
|
}else{
|
|
try {
|
|
const decoded = atob(privateKeyInput.value)
|
|
const bytes = new Uint8Array(decoded.length)
|
|
for (let i = 0; i < decoded.length; i++) {
|
|
bytes[i] = decoded.charCodeAt(i)
|
|
}
|
|
if (bytes.length !== 32) {
|
|
throw new Error('Tamanho inválido')
|
|
}
|
|
array = bytes
|
|
} catch (e) {
|
|
array = new Uint8Array(32)
|
|
crypto.getRandomValues(array)
|
|
privateKeyInput.value = btoa(String.fromCharCode(...array))
|
|
}
|
|
}
|
|
generatePublicKey(array)
|
|
|
|
}
|
|
|
|
function generatePublicKey(privateKeyBytes) {
|
|
const publicKeyBytes = secp.getPublicKey(privateKeyBytes)
|
|
publicKeyB64.value = btoa(String.fromCharCode(...publicKeyBytes))
|
|
}
|
|
|
|
function onSwitchChanged(newValue) {
|
|
privateKeyInput.value = ""
|
|
privateKeyB64.value = ""
|
|
publicKeyB64.value = ""
|
|
}
|
|
|
|
function copy(text){
|
|
navigator.clipboard.writeText(text)
|
|
}
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<TabPanel>
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle class="flex items-center gap-2 text-yellow-400">
|
|
<KeyIcon class="h-5 w-5" />
|
|
Create New User
|
|
</CardTitle>
|
|
<CardDescription class="text-slate-200">
|
|
Generate a new ECDSA keypair for user authentication
|
|
</CardDescription>
|
|
</CardHeader>
|
|
|
|
<CardContent class=" space-y-2">
|
|
<!-- Private key Characteres input -->
|
|
<div class="space-y-2">
|
|
<div class="flex flex-row gap-4">
|
|
<Label>Private Key</Label>
|
|
<ToogleSwitch v-model="isTextEnabled" @update:modelValue="onSwitchChanged"/>
|
|
<Label>Text Password</Label>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<InputText id="privateKey" type="password" v-model="privateKeyInput" placeholder="" class="border-gray-700 bg-slate-300 w-full"/>
|
|
<Button @click="generate()" class="gap-2">
|
|
<ArrowPathIcon class="h-4 w-4"/>
|
|
<span v-if="!privateKeyInput">Generate</span>
|
|
</Button>
|
|
<Button v-if="privateKeyInput" @click="copy(privateKeyInput)" class="flex items-center gap-2">
|
|
<ClipboardDocumentIcon class="h-4 w-4"/>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<!-- Public Key -->
|
|
<div class="space-y-2">
|
|
<Label forId="publicKey" class="text-slate-300">Public Key</Label>
|
|
<div class="flex gap-2">
|
|
<InputText id="publicKey" type="text" v-model="publicKeyB64" placeholder="" class="border-gray-700 bg-slate-300 w-full"/>
|
|
<Button @click="copy(publicKeyB64)" class="flex items-center gap-2">
|
|
<ClipboardDocumentIcon class="h-4 w-4"/>
|
|
Copy
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<!-- Private Key -->
|
|
<div class="space-y-2" v-if="isTextEnabled">
|
|
<Label forId="privateKeyB64" class="text-slate-300">Private Key</Label>
|
|
<div class="flex gap-2">
|
|
<InputText id="privateKeyB64" type="password" v-model="privateKeyB64" placeholder="" class="border-gray-700 bg-slate-300 w-full"/>
|
|
<Button @click="copy(privateKeyB64)" class="flex items-center gap-2">
|
|
<ClipboardDocumentIcon class="h-4 w-4"/>
|
|
Copy
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabPanel>
|
|
</template> |