it-tools/src/tools/bip39-generator/bip39-generator.vue
2022-04-11 23:08:50 +02:00

147 lines
No EOL
4.6 KiB
Vue

<template>
<div>
<n-card>
<n-grid cols="3" x-gap="12">
<n-gi span="1">
<n-form-item label="Language:">
<n-select v-model:value="language"
:options="Object.keys(languages).map(label => ({ label, value: label }))" />
</n-form-item>
</n-gi>
<n-gi span="2">
<n-form-item label="Entropy (seed):" :feedback="entropyValidation.message"
:validation-status="entropyValidation.status">
<n-input-group>
<n-input v-model:value="entropy" placeholder="Your string..." />
<n-button @click="refreshEntropy">
<n-icon size="22">
<Refresh />
</n-icon>
</n-button>
<n-button @click="copyEntropy">
<n-icon size="22">
<Copy />
</n-icon>
</n-button>
</n-input-group>
</n-form-item>
</n-gi>
</n-grid>
<n-form-item label="Passphrase (mnemonic):" :feedback="mnemonicValidation.message"
:validation-status="mnemonicValidation.status">
<n-input-group>
<n-input style="text-align: center; flex: 1;" v-model:value="passphrase"
placeholder="Your mnemonic..." autocomplete="off" autocorrect="off" autocapitalize="off"
spellcheck="false" />
<n-button @click="copyPassphrase">
<n-icon size="22" :component="Copy" />
</n-button>
</n-input-group>
</n-form-item>
</n-card>
</div>
</template>
<script setup lang="ts">
import { useCopy } from '@/composable/copy';
import { ref, computed } from 'vue'
import {
entropyToMnemonic,
englishWordList,
chineseSimplifiedWordList,
chineseTraditionalWordList,
czechWordList,
frenchWordList,
italianWordList,
japaneseWordList,
koreanWordList,
portugueseWordList,
spanishWordList,
generateEntropy,
mnemonicToEntropy
} from '@it-tools/bip39'
import { Copy, Refresh } from '@vicons/tabler'
import { useValidation } from '@/composable/validation';
const languages = {
'English': englishWordList,
'Chinese simplified': chineseSimplifiedWordList,
'Chinese traditional': chineseTraditionalWordList,
'Czech': czechWordList,
'French': frenchWordList,
'Italian': italianWordList,
'Japanese': japaneseWordList,
'Korean': koreanWordList,
'Portuguese': portugueseWordList,
'Spanish': spanishWordList
}
const entropy = ref(generateEntropy())
const passphraseInput = ref('')
const language = ref<keyof typeof languages>('English')
const passphrase = computed({
get() {
try {
return entropyToMnemonic(entropy.value, languages[language.value])
} catch (_) {
return passphraseInput.value
}
},
set(value: string) {
passphraseInput.value = value
try {
entropy.value = mnemonicToEntropy(value, languages[language.value])
} catch (_) {
entropy.value = ''
}
}
})
const entropyValidation = useValidation({
source: entropy,
rules: [
{
validator: (value) => value === '' || (value.length <= 32 && value.length >= 16 && value.length % 4 === 0),
message: 'Entropy length should be >= 16, <= 32 and be a multiple of 4'
},
{
validator: (value) => /^[a-fA-F0-9]*$/.test(value),
message: 'Entropy should an hexadecimal number'
}
]
})
const mnemonicValidation = useValidation({
source: passphrase,
rules: [
{
validator: (value) => {
try {
mnemonicToEntropy(value)
return true
} catch (_) {
return false
}
},
message: 'Invalid mnemonic'
}
]
})
function refreshEntropy() {
entropy.value = generateEntropy()
}
const { copy: copyEntropy } = useCopy({ source: entropy, text: 'Entropy copied to the clipboard' })
const { copy: copyPassphrase } = useCopy({ source: passphrase, text: 'Passphrase copied to the clipboard' })
</script>
<style lang="scss" scoped>
</style>