Skip to content

Commit

Permalink
Merge pull request #133 from dwelman/upload-credential
Browse files Browse the repository at this point in the history
Allows for the upload of a credential directly into a wallet
  • Loading branch information
reinkrul authored Nov 11, 2024
2 parents 78d598d + f10d1b6 commit f37cdb7
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 2 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ During front-end development, you probably want to use the real filesystem and w
make dev
```

You can access the website at `http://localhost:1305/` by default

The API and domain types are generated from the `api/api.yaml`.
```shell
make gen-api
Expand Down
11 changes: 10 additions & 1 deletion web/src/admin/IdentityDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@
<p v-else>
No credentials in wallet.
</p>
<br>
<button
id="upload-credential-button"
@click="$router.push({name: 'admin.uploadCredential', params: {subjectID: this.$route.params.subjectID}})"
class="btn btn-primary"
>
Upload
</button>
</section>
</div>
</div>
Expand All @@ -107,9 +115,10 @@
import DiscoveryServiceDefinition from "./DiscoveryServiceDefinition";
import ErrorMessage from "../components/ErrorMessage.vue";
import UploadCredential from "./credentials/UploadCredential.vue";
export default {
components: {ErrorMessage},
components: {ErrorMessage, UploadCredential},
data() {
return {
fetchError: undefined,
Expand Down
17 changes: 16 additions & 1 deletion web/src/admin/credentials/IssueCredential.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

<section v-if="issuedCredential">
<header>Issued Credential</header>
<button class="btn btn-primary" @click="copyToClipboard">Copy to Clipboard</button>
<pre>{{ JSON.stringify(issuedCredential, null, 2) }}</pre>
</section>

Expand Down Expand Up @@ -86,7 +87,12 @@
</div>
</div>
</template>

<style scoped>
button.btn.btn-primary {
display: block;
margin-bottom: 1rem;
}
</style>
<script>
import templates from "./templates";
import ErrorMessage from "../../components/ErrorMessage.vue";
Expand Down Expand Up @@ -187,6 +193,15 @@ export default {
.catch(response => {
this.fetchError = response
})
},
copyToClipboard() {
navigator.clipboard.writeText(JSON.stringify(this.issuedCredential, null, 2))
.then(() => {
this.$emit('statusUpdate', 'Credential copied to clipboard')
})
.catch(err => {
this.fetchError = 'Failed to copy credential: ' + err
})
}
}
}
Expand Down
51 changes: 51 additions & 0 deletions web/src/admin/credentials/UploadCredential.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<template>
<modal-window :cancelRoute="{name: 'admin.identityDetails', params: {subjectID: this.$route.params.subjectID}}" :confirmFn="confirm" confirmText="Upload Credential"
title="Upload a Credential JSON" type="add">

<p class="mb-3 text-sm">
Here you can add a credential issued by another party to be stored in your wallet. Paste the JSON object below.
</p>

<ErrorMessage v-if="apiError" :message="apiError" title="Could not upload credential"/>

<div class="mt-4">
<upload-credential-form mode="new" :value="credential" @input="(credentialPaste)=> {credential = credentialPaste}"/>
</div>
</modal-window>
</template>

<script>
import ModalWindow from '../../components/ModalWindow.vue'
import UploadCredentialForm from "./UploadCredentialForm.vue";
import ErrorMessage from "../../components/ErrorMessage.vue";
export default {
components: {
ErrorMessage,
ModalWindow,
UploadCredentialForm
},
created() {
this.subjectID = this.$route.params.subjectID;
},
data () {
return {
apiError: '',
subjectID: '',
credential: {}
}
},
methods: {
confirm () {
this.$api.post(`api/proxy/internal/vcr/v2/holder/${this.subjectID}/vc`, this.credential)
.then(() => {
this.$emit('uploadCredential', 'Verifiable Credential issued, and loaded into wallet')
this.$router.push({name: 'admin.identityDetails', params: {subjectID: this.subjectID}})
})
.catch(reason => {
this.apiError = reason
})
}
}
}
</script>
33 changes: 33 additions & 0 deletions web/src/admin/credentials/UploadCredentialForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<template>
<form class="space-y-3">
<div>
<div v-if="error" class="text-red-500">{{ error }}</div>
<textarea v-model="localValue" rows="10" cols="30"></textarea>
</div>
</form>
</template>
<script>
export default {
props: {
value: Object,
mode: String
},
data () {
return {
localValue: JSON.stringify(this.value, null, 2)
}
},
emits: ['input'],
watch: {
localValue (newValue) {
try {
this.error = '';
let parsedInput = JSON.parse(newValue)
this.$emit('input', parsedInput);
} catch (e) {
this.error = 'Invalid JSON format';
}
}
}
}
</script>
6 changes: 6 additions & 0 deletions web/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Api from './plugins/api'
import IdentityDetails from "./admin/IdentityDetails.vue";
import IssueCredential from "./admin/credentials/IssueCredential.vue";
import ActivateDiscoveryService from "./admin/ActivateDiscoveryService.vue";
import UploadCredential from "./admin/credentials/UploadCredential.vue";

const routes = [
{
Expand Down Expand Up @@ -51,6 +52,11 @@ const routes = [
name: 'admin.identityDetails',
component: IdentityDetails,
},
{
path: 'id/:subjectID/upload',
name: 'admin.uploadCredential',
component: UploadCredential,
},
{
path: 'id/:subjectID/discovery/:discoveryServiceID/activate',
name: 'admin.activateDiscoveryService',
Expand Down

0 comments on commit f37cdb7

Please sign in to comment.