feat: mii rendering
This commit is contained in:
parent
3a2e4c9b63
commit
fb4d790b3d
3 changed files with 67 additions and 7 deletions
|
|
@ -11,6 +11,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@auth/prisma-adapter": "2.7.2",
|
||||
"@pretendonetwork/mii-js": "github:PretendoNetwork/mii-js#publish-and-eslint",
|
||||
"@prisma/client": "^6.5.0",
|
||||
"@trafficlunar/asmcrypto.js": "^1.0.2",
|
||||
"@yudiel/react-qr-scanner": "2.2.2-beta.2",
|
||||
|
|
@ -18,6 +19,7 @@
|
|||
"jsqr": "^1.4.0",
|
||||
"next": "15.2.4",
|
||||
"next-auth": "5.0.0-beta.25",
|
||||
"qrcode-generator": "^1.4.4",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-dropzone": "^14.3.8",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ importers:
|
|||
'@auth/prisma-adapter':
|
||||
specifier: 2.7.2
|
||||
version: 2.7.2(@prisma/client@6.5.0(prisma@6.5.0(typescript@5.8.2))(typescript@5.8.2))
|
||||
'@pretendonetwork/mii-js':
|
||||
specifier: github:PretendoNetwork/mii-js#publish-and-eslint
|
||||
version: https://codeload.github.com/PretendoNetwork/mii-js/tar.gz/8b857460b61dde9729eff848d99fd3ef9128f2a5
|
||||
'@prisma/client':
|
||||
specifier: ^6.5.0
|
||||
version: 6.5.0(prisma@6.5.0(typescript@5.8.2))(typescript@5.8.2)
|
||||
|
|
@ -32,6 +35,9 @@ importers:
|
|||
next-auth:
|
||||
specifier: 5.0.0-beta.25
|
||||
version: 5.0.0-beta.25(next@15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
||||
qrcode-generator:
|
||||
specifier: ^1.4.4
|
||||
version: 1.4.4
|
||||
react:
|
||||
specifier: ^19.0.0
|
||||
version: 19.1.0
|
||||
|
|
@ -626,6 +632,10 @@ packages:
|
|||
'@panva/hkdf@1.2.1':
|
||||
resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==}
|
||||
|
||||
'@pretendonetwork/mii-js@https://codeload.github.com/PretendoNetwork/mii-js/tar.gz/8b857460b61dde9729eff848d99fd3ef9128f2a5':
|
||||
resolution: {tarball: https://codeload.github.com/PretendoNetwork/mii-js/tar.gz/8b857460b61dde9729eff848d99fd3ef9128f2a5}
|
||||
version: 1.0.4
|
||||
|
||||
'@prisma/client@6.5.0':
|
||||
resolution: {integrity: sha512-M6w1Ql/BeiGoZmhMdAZUXHu5sz5HubyVcKukbLs3l0ELcQb8hTUJxtGEChhv4SVJ0QJlwtLnwOLgIRQhpsm9dw==}
|
||||
engines: {node: '>=18.18'}
|
||||
|
|
@ -1001,6 +1011,9 @@ packages:
|
|||
barcode-detector@3.0.1:
|
||||
resolution: {integrity: sha512-3fCzG/Py4SVgZJhubD1mt7rVprtHEVWrxQN4FUOG0oulPE4193evbgyptxcOYsfTNEtMlWc+Ec9tdxhjlR4/Ww==}
|
||||
|
||||
bit-buffer@0.2.5:
|
||||
resolution: {integrity: sha512-x1yGnmXvFg6e3DiyRztElbcn1bsCTFSoM/ncAzY62uE0JdTl5xlKJd0ooqLYoPbhdsnpehSIQrdIvclcZJYwiA==}
|
||||
|
||||
brace-expansion@1.1.11:
|
||||
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||
|
||||
|
|
@ -1934,6 +1947,9 @@ packages:
|
|||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
qrcode-generator@1.4.4:
|
||||
resolution: {integrity: sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==}
|
||||
|
||||
queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
|
|
@ -2722,6 +2738,10 @@ snapshots:
|
|||
|
||||
'@panva/hkdf@1.2.1': {}
|
||||
|
||||
'@pretendonetwork/mii-js@https://codeload.github.com/PretendoNetwork/mii-js/tar.gz/8b857460b61dde9729eff848d99fd3ef9128f2a5':
|
||||
dependencies:
|
||||
bit-buffer: 0.2.5
|
||||
|
||||
'@prisma/client@6.5.0(prisma@6.5.0(typescript@5.8.2))(typescript@5.8.2)':
|
||||
optionalDependencies:
|
||||
prisma: 6.5.0(typescript@5.8.2)
|
||||
|
|
@ -3109,6 +3129,8 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- '@types/emscripten'
|
||||
|
||||
bit-buffer@0.2.5: {}
|
||||
|
||||
brace-expansion@1.1.11:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
|
|
@ -4201,6 +4223,8 @@ snapshots:
|
|||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
qrcode-generator@1.4.4: {}
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
|
||||
react-dom@19.1.0(react@19.1.0):
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
Loading…
Reference in a new issue