Skip to content

Commit

Permalink
feat(coldmfa): Add a UI option for manual import
Browse files Browse the repository at this point in the history
  • Loading branch information
ThetaSinner committed Oct 13, 2024
1 parent d9554f3 commit 250d152
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 13 deletions.
1 change: 1 addition & 0 deletions coldmfa/app/src/components/CodeSummaryLine.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ describe('CodeSummaryLine', () => {

it('move between groups', async () => {
const wrapper = mount(Host, {
attachTo: document.body,
props: {
groupId,
codeId
Expand Down
38 changes: 37 additions & 1 deletion coldmfa/app/src/components/CreateCode.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ describe('CreateCode', () => {
}
})
await wrapper
.get('input')
.get('input[data-test-id="code-original"]')
.setValue(
'otpauth://totp/EphyraSoftware:test-a?algorithm=SHA1&digits=6&issuer=EphyraSoftware&period=30&secret=NL6ZHWZXRNCNNIHQKDXK2Q4GGA3PKQD3'
)
Expand All @@ -127,4 +127,40 @@ describe('CreateCode', () => {

expect(wrapper.html()).toContain('Error creating your code: A test error')
})

it('create code manual', async () => {
const wrapper = mount(CreateCode, {
global: {
provide: {
client
}
},
props: {
groupId
}
})

// Switch to the manual tab
await wrapper.get('a[data-test-id="manual"]').trigger('click')

// Fill out the form, leaving defaults in place
await wrapper.get('input[data-test-id="code-provider"]').setValue('EphyraSoftware')

await wrapper.get('input[data-test-id="code-name"]').setValue('test-a')

await wrapper
.get('input[data-test-id="code-secret"]')
.setValue('NL6ZHWZXRNCNNIHQKDXK2Q4GGA3PKQD3')

// Submit the form to creat a code
await wrapper.get('button').trigger('submit')

await flushPromises()

// Check that the created code was put in the store
const groupsStore = useGroupsStore()
expect(groupsStore.groups).toHaveLength(1)
const codes = groupsStore.groupCodes(groupId)
expect(codes).toHaveLength(1)
})
})
115 changes: 103 additions & 12 deletions coldmfa/app/src/components/CreateCode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,39 @@ const emit = defineEmits<{
const client = inject<AxiosInstance>('client') as AxiosInstance
const groupsStore = useGroupsStore()
const activeTab = ref<'url' | 'manual'>('url')
const input = useTemplateRef('codeNameInput')
// For URL input
const original = ref('')
// For manual input
const provider = ref('')
const codeName = ref('')
const secret = ref('')
const algorithm = ref('SHA1')
const digits = ref('6')
const period = ref('30')
// For error message
const errMsg = ref('')
onMounted(() => {
input.value?.focus()
})
const storeCode = async () => {
let codeUrl = original.value
if (activeTab.value === 'manual') {
codeUrl = `otpauth://totp/${provider.value}:${codeName.value}?algorithm=${algorithm.value}&digits=${digits.value}&issuer=${provider.value}&period=${period.value}&secret=${secret.value}`
}
try {
const groupId = props.groupId
const response: AxiosResponse<CodeSummary | ApiError> = await client.post(
`api/groups/${groupId}/codes`,
{
original: original.value
original: codeUrl
},
{
validateStatus: (status) => status === 201
Expand Down Expand Up @@ -59,17 +76,91 @@ const storeCode = async () => {

<template>
<p class="text-xl bold">Create a new code</p>
<form class="flex flex-col py-2" @submit.prevent.stop="storeCode">
<input
type="text"
placeholder="URL for the One Time Password"
name="original"
class="input input-bordered input-accent w-full max-w-s"
autocomplete="off"
ref="codeNameInput"
v-model="original"
data-test-id="code-original"
/>

<div role="tablist" class="tabs tabs-boxed">
<a
role="tab"
class="tab"
:class="{ 'tab-active': activeTab === 'url' }"
@click="activeTab = 'url'"
>From URL</a
>
<a
role="tab"
class="tab"
:class="{ 'tab-active': activeTab === 'manual' }"
data-test-id="manual"
@click="activeTab = 'manual'"
>Manual</a
>
</div>

<form class="flex flex-col py-2 gap-3" @submit.prevent.stop="storeCode">
<template v-if="activeTab === 'url'">
<input
type="text"
placeholder="URL for the One Time Password"
name="original"
class="input input-bordered input-accent w-full max-w-s"
autocomplete="off"
ref="codeNameInput"
v-model="original"
data-test-id="code-original"
/>
</template>
<template v-else-if="activeTab === 'manual'">
<input
type="text"
placeholder="Provider"
class="input input-bordered input-accent w-full max-w-s"
v-model="provider"
data-test-id="code-provider"
/>

<input
type="text"
placeholder="Name"
class="input input-bordered input-accent w-full max-w-s"
v-model="codeName"
data-test-id="code-name"
/>

<input
type="password"
placeholder="Secret"
class="input input-bordered input-accent w-full max-w-s"
v-model="secret"
data-test-id="code-secret"
/>

<select
v-model="algorithm"
data-test-id="code-algorithm"
class="select select-bordered w-full max-w-s"
>
<option value="SHA1">SHA1</option>
<option value="SHA256">SHA256</option>
<option value="SHA512">SHA512</option>
</select>

<select
v-model="digits"
data-test-id="code-digits"
class="select select-bordered w-full max-w-s"
>
<option value="6">6</option>
<option value="8">8</option>
</select>

<input
type="number"
placeholder="Period"
class="input input-bordered input-accent w-full max-w-s"
v-model="period"
data-test-id="code-period"
/>
</template>

<p v-if="errMsg" class="text-red-500 py-2">Error creating your code: {{ errMsg }}</p>

<div class="flex flex-row justify-end my-2 mx-1">
Expand Down

0 comments on commit 250d152

Please sign in to comment.