handy online tools for AT Protocol boat.kelinci.net
atproto bluesky atcute typescript solidjs
20
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: upgrade to atcute/crypto alpha

Mary b0b2c9db b726e88b

+76 -62
+1 -1
package.json
··· 11 11 "@atcute/car": "^2.0.0", 12 12 "@atcute/cbor": "^2.0.0", 13 13 "@atcute/client": "^2.0.6", 14 - "@atcute/crypto": "^1.0.2", 14 + "@atcute/crypto": "2.0.0-alpha.1", 15 15 "@atcute/multibase": "^1.0.1", 16 16 "@badrap/valita": "^0.4.2", 17 17 "@mary/events": "npm:@jsr/mary__events@^0.1.0",
+9 -18
pnpm-lock.yaml
··· 21 21 specifier: ^2.0.6 22 22 version: 2.0.6 23 23 '@atcute/crypto': 24 - specifier: ^1.0.2 25 - version: 1.0.2 24 + specifier: 2.0.0-alpha.1 25 + version: 2.0.0-alpha.1 26 26 '@atcute/multibase': 27 27 specifier: ^1.0.1 28 28 version: 1.0.1 ··· 109 109 '@atcute/client@2.0.6': 110 110 resolution: {integrity: sha512-mhdqEicGUx0s5HTFOLpz91rcLS9j/g63de0nmAqv7blhU3j+xBf4le54qr2YIXNfnReZI7EwLYLX/YIBez4LGA==} 111 111 112 - '@atcute/crypto@1.0.2': 113 - resolution: {integrity: sha512-jKS6JBiuW/5ljiTIrXD98Tp2oLXuoTBgkhQZt7pA/+j3juzsSuS7w16Ldw8p/1XGuhr8yzpMspvvp30QYXQzeQ==} 112 + '@atcute/crypto@2.0.0-alpha.1': 113 + resolution: {integrity: sha512-nVk4VC4esAIKq1kFc75Y5R2Y5cO/HtCh+li9lRSB4b5PSyL8mHoZNoR0OLa1VQhc1FDvykAD56iXvUz6XnCKCw==} 114 114 115 115 '@atcute/multibase@1.0.1': 116 116 resolution: {integrity: sha512-lOVNX+pKwxn/OKCEyM7D/LCBPhnW0Ex0JcDRRTwuuI3w2GbrCut41rUF8uZUsrbrplNLMoj7xZkz9EDku/5mvQ==} ··· 572 572 '@jsr/mary__tar@0.2.4': 573 573 resolution: {integrity: sha512-jFjPcZj8DRSukPLZOt6+h74cVFdfdTMG9gzbW67YByCJTD52PEpe2sNcfCSw4mQ8hZBNgwiufCPyYL8hR9yicA==, tarball: https://npm.jsr.io/~/11/@jsr/mary__tar/0.2.4.tgz} 574 574 575 - '@noble/curves@1.7.0': 576 - resolution: {integrity: sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==} 577 - engines: {node: ^14.21.3 || >=16} 578 - 579 - '@noble/hashes@1.6.0': 580 - resolution: {integrity: sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ==} 581 - engines: {node: ^14.21.3 || >=16} 575 + '@noble/secp256k1@2.1.0': 576 + resolution: {integrity: sha512-XLEQQNdablO0XZOIniFQimiXsZDNwaYgL96dZwC54Q30imSbAOFf3NKtepc+cXyuZf5Q1HCgbqgZ2UFFuHVcEw==} 582 577 583 578 '@nodelib/fs.scandir@2.1.5': 584 579 resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} ··· 1609 1604 1610 1605 '@atcute/client@2.0.6': {} 1611 1606 1612 - '@atcute/crypto@1.0.2': 1607 + '@atcute/crypto@2.0.0-alpha.1': 1613 1608 dependencies: 1614 1609 '@atcute/multibase': 1.0.1 1615 - '@noble/curves': 1.7.0 1610 + '@noble/secp256k1': 2.1.0 1616 1611 1617 1612 '@atcute/multibase@1.0.1': {} 1618 1613 ··· 1949 1944 1950 1945 '@jsr/mary__tar@0.2.4': {} 1951 1946 1952 - '@noble/curves@1.7.0': 1953 - dependencies: 1954 - '@noble/hashes': 1.6.0 1955 - 1956 - '@noble/hashes@1.6.0': {} 1947 + '@noble/secp256k1@2.1.0': {} 1957 1948 1958 1949 '@nodelib/fs.scandir@2.1.5': 1959 1950 dependencies:
+31 -16
src/views/crypto/crypto-generate.tsx
··· 1 1 import { createSignal, Show } from 'solid-js'; 2 2 3 - import { 4 - createP256Keypair, 5 - createSecp256k1Keypair, 6 - type P256PrivateKeyExportable, 7 - type Secp256k1PrivateKeyExportable, 8 - } from '@atcute/crypto'; 3 + import { type DidKeyString, P256PrivateKeyExportable, Secp256k1PrivateKeyExportable } from '@atcute/crypto'; 9 4 10 5 import { useTitle } from '~/lib/navigation/router'; 11 6 12 7 import Button from '~/components/inputs/button'; 13 8 import RadioInput from '~/components/inputs/radio-input'; 14 9 15 - type KeyType = 'nistp256' | 'secp256k1'; 10 + type KeyType = 'p256' | 'secp256k1'; 16 11 17 12 type Keypair = P256PrivateKeyExportable | Secp256k1PrivateKeyExportable; 18 13 14 + interface KeypairResult { 15 + type: KeyType; 16 + publicDidKey: DidKeyString; 17 + privateHex: string; 18 + privateMultikey: string; 19 + } 20 + 19 21 const CryptoGeneratePage = () => { 20 22 const [type, setType] = createSignal<KeyType>('secp256k1'); 21 - const [result, setResult] = createSignal<Keypair>(); 23 + const [result, setResult] = createSignal<KeypairResult>(); 22 24 23 25 useTitle(() => `Generate secret keys — boat`); 24 26 ··· 37 39 const $type = type(); 38 40 let keypair: Keypair; 39 41 40 - if ($type === 'nistp256') { 41 - keypair = createP256Keypair(); 42 + if ($type === 'p256') { 43 + keypair = await P256PrivateKeyExportable.createKeypair(); 42 44 } else if ($type === 'secp256k1') { 43 - keypair = createSecp256k1Keypair(); 45 + keypair = await Secp256k1PrivateKeyExportable.createKeypair(); 44 46 } else { 45 47 return; 46 48 } 47 49 48 - setResult(keypair); 50 + const [publicDidKey, privateHex, privateMultikey] = await Promise.all([ 51 + keypair.exportPublicKey('did'), 52 + keypair.exportPrivateKey('rawHex'), 53 + keypair.exportPrivateKey('multikey'), 54 + ]); 55 + 56 + const result: KeypairResult = { 57 + type: keypair.type, 58 + publicDidKey, 59 + privateHex, 60 + privateMultikey, 61 + }; 62 + 63 + setResult(result); 49 64 }} 50 65 class="flex flex-col gap-4 p-4" 51 66 > ··· 56 71 value={type()} 57 72 options={[ 58 73 { value: 'secp256k1', label: `ES256K (secp256k1) private key` }, 59 - { value: 'nistp256', label: `ES256 (nistp256) private key` }, 74 + { value: 'p256', label: `ES256 (p256) private key` }, 60 75 ]} 61 76 onChange={setType} 62 77 /> ··· 77 92 78 93 <div> 79 94 <p class="font-semibold text-gray-600">Public key (did:key)</p> 80 - <span class="font-mono">{/* @once */ keypair.did()}</span> 95 + <span class="font-mono">{/* @once */ keypair.publicDidKey}</span> 81 96 </div> 82 97 83 98 <div> 84 99 <p class="font-semibold text-gray-600">Private key (hex)</p> 85 - <span class="font-mono">{/* @once */ keypair.export('hex')}</span> 100 + <span class="font-mono">{/* @once */ keypair.privateHex}</span> 86 101 </div> 87 102 88 103 <div> 89 104 <p class="font-semibold text-gray-600">Private key (multikey)</p> 90 - <span class="font-mono">{/* @once */ keypair.export('multikey')}</span> 105 + <span class="font-mono">{/* @once */ keypair.privateMultikey}</span> 91 106 </div> 92 107 </div> 93 108 )}
+1 -1
src/views/identity/plc-applicator/page.tsx
··· 35 35 recommendedDidDoc: ComAtprotoIdentityGetRecommendedDidCredentials.Output; 36 36 } 37 37 38 - type Keypair = P256PrivateKey | Secp256k1PrivateKey; 38 + export type Keypair = P256PrivateKey | Secp256k1PrivateKey; 39 39 export interface PrivateKeySigningMethod { 40 40 type: 'private_key'; 41 41 keypair: Keypair;
+34 -26
src/views/identity/plc-applicator/steps/step2_private-key-input.tsx
··· 10 10 import TextInput from '~/components/inputs/text-input'; 11 11 import { Stage, StageActions, StageErrorView, WizardStepProps } from '~/components/wizard'; 12 12 13 - import { PlcApplicatorConstraints } from '../page'; 13 + import type { Keypair, PlcApplicatorConstraints, PrivateKeySigningMethod } from '../page'; 14 14 15 15 type KeyType = 'p256' | 'secp256k1'; 16 16 type KeyFormat = 'hex' | 'multikey'; ··· 41 41 }); 42 42 43 43 const mutation = createMutation({ 44 - async mutationFn({ type, input }: { type: KeyType; input: string }) { 44 + async mutationFn({ type, input }: { type: KeyType; input: string }): Promise<PrivateKeySigningMethod> { 45 + let keypair: Keypair | undefined; 46 + 45 47 if (HEX_REGEX.test(input)) { 46 - const privateKey = fromBase16(input); 48 + const privateKeyBytes = fromBase16(input); 47 49 48 50 switch (type) { 49 51 case 'p256': { 50 - return new P256PrivateKey(privateKey); 52 + keypair = await P256PrivateKey.importRaw(privateKeyBytes); 53 + break; 51 54 } 52 55 case 'secp256k1': { 53 - return new Secp256k1PrivateKey(privateKey); 56 + keypair = await Secp256k1PrivateKey.importRaw(privateKeyBytes); 57 + break; 58 + } 59 + default: { 60 + throw new Error(`unsupported "${type}" type`); 54 61 } 55 62 } 56 - 57 - throw new Error(`unsupported "${type}" type`); 58 - } 59 - 60 - if (MULTIKEY_REGEX.test(input)) { 63 + } else if (MULTIKEY_REGEX.test(input)) { 61 64 const match = parsePrivateMultikey(input); 62 - const privateKey = match.privateKey; 65 + const privateKeyBytes = match.privateKeyBytes; 63 66 64 67 switch (match.type) { 65 68 case 'p256': { 66 - return new P256PrivateKey(privateKey); 69 + keypair = await P256PrivateKey.importRaw(privateKeyBytes); 70 + break; 67 71 } 68 72 case 'secp256k1': { 69 - return new Secp256k1PrivateKey(privateKey); 73 + keypair = await Secp256k1PrivateKey.importRaw(privateKeyBytes); 74 + break; 75 + } 76 + default: { 77 + throw new Error(`unsupported "${type}" type`); 70 78 } 71 79 } 72 - 73 - throw new Error(`unsupported "${type}" type`); 80 + } else { 81 + throw new Error(`unknown input format`); 74 82 } 75 83 76 - throw new Error(`unknown input format`); 84 + return { 85 + type: 'private_key', 86 + didPublicKey: await keypair.exportPublicKey('did'), 87 + keypair: keypair, 88 + }; 77 89 }, 78 90 onMutate() { 79 91 setError(); 80 92 }, 81 - onSuccess(keypair) { 93 + onSuccess(method) { 82 94 onNext('Step3_OperationSelect', { 83 95 info: data.info, 84 - method: { 85 - type: 'private_key', 86 - didPublicKey: keypair.did(), 87 - keypair: keypair, 88 - }, 96 + method, 89 97 }); 90 98 }, 91 99 onError(error) { ··· 113 121 > 114 122 <Switch> 115 123 <Match when={!isActive() && mutation.data} keyed> 116 - {(keypair) => ( 124 + {(method) => ( 117 125 <div class="break-words"> 118 126 <p> 119 - <b>{/* @once */ keypair.type}</b> keypair provided. 127 + <b>{/* @once */ method.keypair.type}</b> keypair provided. 120 128 </p> 121 - <p class="mt-2 font-mono font-medium">{/* @once */ keypair.did()}</p> 129 + <p class="mt-2 font-mono font-medium">{/* @once */ method.didPublicKey}</p> 122 130 </div> 123 131 )} 124 132 </Match> 125 133 126 134 <Match when> 127 135 <TextInput 128 - label="Private key (hex or multikey)" 136 + label="Private key (raw hex or multikey)" 129 137 blurb="This app runs locally on your browser, your private key stays entirely within your device." 130 138 type={isActive() ? 'text' : 'password'} 131 139 autocomplete="off"