|
@ -21,8 +21,8 @@ |
|
|
</h1> |
|
|
</h1> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-8"> |
|
|
<div> |
|
|
<h2 class="text-xl font-bold mb-4">Notiwind Alert Test Suite</h2> |
|
|
<h2 class="text-xl font-bold mb-4">Notiwind Alerts</h2> |
|
|
|
|
|
|
|
|
<button |
|
|
<button |
|
|
@click=" |
|
|
@click=" |
|
@ -154,8 +154,8 @@ |
|
|
</button> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div> |
|
|
<div class="mt-8"> |
|
|
<h2 class="text-xl font-bold mb-4">Share Image</h2> |
|
|
<h2 class="text-xl font-bold mb-4">Image Sharing</h2> |
|
|
Populates the "shared-photo" view as if they used "share_target". |
|
|
Populates the "shared-photo" view as if they used "share_target". |
|
|
<input type="file" @change="uploadFile" /> |
|
|
<input type="file" @change="uploadFile" /> |
|
|
<router-link |
|
|
<router-link |
|
@ -169,22 +169,65 @@ |
|
|
Go to Shared Page |
|
|
Go to Shared Page |
|
|
</router-link> |
|
|
</router-link> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div class="mt-8"> |
|
|
|
|
|
<h2 class="text-xl font-bold mb-4">Passkeys</h2> |
|
|
|
|
|
<button |
|
|
|
|
|
@click="register()" |
|
|
|
|
|
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2" |
|
|
|
|
|
> |
|
|
|
|
|
Register |
|
|
|
|
|
</button> |
|
|
|
|
|
<button |
|
|
|
|
|
@click="create()" |
|
|
|
|
|
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2" |
|
|
|
|
|
> |
|
|
|
|
|
Create |
|
|
|
|
|
</button> |
|
|
|
|
|
<button |
|
|
|
|
|
@click="verify()" |
|
|
|
|
|
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2" |
|
|
|
|
|
> |
|
|
|
|
|
Verify |
|
|
|
|
|
</button> |
|
|
|
|
|
</div> |
|
|
</section> |
|
|
</section> |
|
|
</template> |
|
|
</template> |
|
|
|
|
|
|
|
|
<script lang="ts"> |
|
|
<script lang="ts"> |
|
|
|
|
|
import { Base64URLString } from "@simplewebauthn/types"; |
|
|
import { ref } from "vue"; |
|
|
import { ref } from "vue"; |
|
|
import { Component, Vue } from "vue-facing-decorator"; |
|
|
import { Component, Vue } from "vue-facing-decorator"; |
|
|
|
|
|
|
|
|
import QuickNav from "@/components/QuickNav.vue"; |
|
|
import QuickNav from "@/components/QuickNav.vue"; |
|
|
import { db } from "@/db/index"; |
|
|
import { db } from "@/db/index"; |
|
|
|
|
|
import { generateRandomBytes } from "@/libs/crypto"; |
|
|
|
|
|
import { |
|
|
|
|
|
createPeerDid, |
|
|
|
|
|
JWK, |
|
|
|
|
|
PeerSetup, |
|
|
|
|
|
registerCredential, |
|
|
|
|
|
verifyJwt, |
|
|
|
|
|
} from "@/libs/didPeer"; |
|
|
|
|
|
|
|
|
const inputFileNameRef = ref<Blob>(); |
|
|
const inputFileNameRef = ref<Blob>(); |
|
|
|
|
|
|
|
|
@Component({ components: { QuickNav } }) |
|
|
@Component({ components: { QuickNav } }) |
|
|
export default class Help extends Vue { |
|
|
export default class Help extends Vue { |
|
|
|
|
|
// for file import |
|
|
fileName?: string; |
|
|
fileName?: string; |
|
|
|
|
|
|
|
|
|
|
|
// for passkeys |
|
|
|
|
|
authenticatorData?: ArrayBuffer; |
|
|
|
|
|
credId?: Base64URLString; |
|
|
|
|
|
jwt?: string; |
|
|
|
|
|
peerSetup?: PeerSetup; |
|
|
|
|
|
publicKeyJwk?: JWK; |
|
|
|
|
|
publicKeyBytes?: Uint8Array; |
|
|
|
|
|
rawId?: Uint8Array; |
|
|
|
|
|
savedCredentialId = ""; |
|
|
|
|
|
userId?: ArrayBuffer; |
|
|
|
|
|
|
|
|
async uploadFile(event: Event) { |
|
|
async uploadFile(event: Event) { |
|
|
inputFileNameRef.value = event.target.files[0]; |
|
|
inputFileNameRef.value = event.target.files[0]; |
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/File |
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/File |
|
@ -214,5 +257,55 @@ export default class Help extends Vue { |
|
|
showFileNextStep() { |
|
|
showFileNextStep() { |
|
|
return !!inputFileNameRef.value; |
|
|
return !!inputFileNameRef.value; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public async register() { |
|
|
|
|
|
this.userId = generateRandomBytes(16).buffer; |
|
|
|
|
|
const encodedUserId = new TextDecoder("utf-8").decode(this.userId); |
|
|
|
|
|
console.log("encodedUserId", encodedUserId); |
|
|
|
|
|
|
|
|
|
|
|
const challenge = generateRandomBytes(32); |
|
|
|
|
|
const cred = await registerCredential( |
|
|
|
|
|
this.userId as Uint8Array, |
|
|
|
|
|
challenge as Uint8Array, |
|
|
|
|
|
); |
|
|
|
|
|
console.log("public key", cred); |
|
|
|
|
|
this.publicKeyJwk = cred.publicKeyJwk; |
|
|
|
|
|
this.publicKeyBytes = cred.publicKeyBytes; |
|
|
|
|
|
this.credId = cred.credId as string; |
|
|
|
|
|
this.rawId = cred.rawId as Uint8Array; |
|
|
|
|
|
this.savedCredentialId = this.credId; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public async create() { |
|
|
|
|
|
const did = createPeerDid(this.publicKeyBytes as Uint8Array); |
|
|
|
|
|
console.log("did", did); |
|
|
|
|
|
const payload = { a: 1 }; |
|
|
|
|
|
this.peerSetup = new PeerSetup(); |
|
|
|
|
|
const rawJwt = await this.peerSetup.createJwt(payload, did, this.credId as string); |
|
|
|
|
|
console.log("raw jwt", rawJwt); |
|
|
|
|
|
this.jwt = rawJwt |
|
|
|
|
|
.replace(/\+/g, "-") |
|
|
|
|
|
.replace(/\//g, "_") |
|
|
|
|
|
.replace(/=+$/, ""); |
|
|
|
|
|
console.log("jwt4url", this.jwt); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public async verify() { |
|
|
|
|
|
if (!this.jwt || !this.peerSetup) { |
|
|
|
|
|
alert("Create a JWT first."); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
const signature = this.jwt.split(".")[2]; |
|
|
|
|
|
const decoded = await verifyJwt( |
|
|
|
|
|
this.jwt || "", |
|
|
|
|
|
this.credId as Base64URLString, |
|
|
|
|
|
this.rawId as Uint8Array, |
|
|
|
|
|
this.peerSetup.authenticatorData as ArrayBuffer, |
|
|
|
|
|
this.peerSetup.clientDataJsonDecoded, |
|
|
|
|
|
this.publicKeyBytes as Uint8Array, |
|
|
|
|
|
signature, |
|
|
|
|
|
); |
|
|
|
|
|
console.log("decoded", decoded); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
</script> |
|
|
</script> |
|
|