feat: mii rendering

This commit is contained in:
trafficlunar 2025-04-04 20:42:03 +01:00
parent 3a2e4c9b63
commit fb4d790b3d
3 changed files with 67 additions and 7 deletions

View file

@ -4,12 +4,14 @@ import { useEffect, useState } from "react";
import { useDropzone } from "react-dropzone";
import { Icon } from "@iconify/react";
import { AES_CCM } from "@trafficlunar/asmcrypto.js";
import Mii from "@pretendonetwork/mii-js";
import qrcode from "qrcode-generator";
import TagSelector from "./submit/tag-selector";
import QrUpload from "./submit/qr-upload";
import QrScanner from "./submit/qr-scanner";
import { AES_CCM } from "@trafficlunar/asmcrypto.js";
const key = new Uint8Array([0x59, 0xfc, 0x81, 0x7e, 0x64, 0x46, 0xea, 0x61, 0x90, 0x34, 0x7b, 0x20, 0xe9, 0xbd, 0xce, 0x52]);
export default function SubmitForm() {
@ -22,10 +24,14 @@ export default function SubmitForm() {
const [isQrScannerOpen, setIsQrScannerOpen] = useState(false);
const [qrBytes, setQrBytes] = useState<Uint8Array>(new Uint8Array());
const [studioUrl, setStudioUrl] = useState<string | undefined>();
const [generatedQrCodeUrl, setGeneratedQrCodeUrl] = useState<string | undefined>();
useEffect(() => {
if (qrBytes.length == 0) return;
const decrypt = async () => {
const decode = async () => {
// Decrypt the QR code
const nonce = qrBytes.subarray(0, 8);
const content = qrBytes.subarray(8, 0x70);
@ -33,17 +39,45 @@ export default function SubmitForm() {
nonceWithZeros.set(nonce, 0);
const decrypted = AES_CCM.decrypt(content, key, nonceWithZeros, undefined, 16);
const result = new Uint8Array([...decrypted.subarray(0, 12), ...qrBytes.subarray(0, 8), ...decrypted.subarray(12, decrypted.length - 4)]);
const result = new Uint8Array(96);
result.set(decrypted.subarray(0, 12), 0);
result.set(nonce, 12);
result.set(decrypted.subarray(12), 20);
console.log(result);
// Convert to Mii class
const buffer = Buffer.from(result);
const mii = new Mii(buffer);
setStudioUrl(mii.studioUrl({ width: 128 }));
// Generate a new QR code for aesthetic reasons
const byteString = String.fromCharCode(...qrBytes);
const generatedCode = qrcode(0, "L");
generatedCode.addData(byteString, "Byte");
generatedCode.make();
setGeneratedQrCodeUrl(generatedCode.createDataURL());
};
decrypt();
decode();
}, [qrBytes]);
return (
<form onSubmit={(e) => e.preventDefault()} className="grid grid-cols-2">
<div className="p-4">
<div className="p-4 flex flex-col gap-2">
<div className="flex justify-center gap-2">
<img
src={studioUrl}
alt="Nintendo Studio URL"
className="aspect-square size-32 bg-orange-100 rounded-xl border-2 border-amber-500 text-[0px]"
/>
<img
src={generatedQrCodeUrl}
alt="Generated QR Code"
className="aspect-square size-32 bg-orange-100 rounded-xl border-2 border-amber-500 text-[0px]"
/>
</div>
<div className="p-2 border-2 bg-orange-100 border-amber-500 rounded-2xl shadow-lg h-48">
<div
{...getRootProps({