···11import type { ComAtprotoIdentitySignPlcOperation } from "@atcute/client/lexicons";
22-import { Secp256k1Keypair } from "@atproto/crypto";
22+import { secp256k1 as k256 } from "@noble/curves/secp256k1";
33import * as ui8 from "uint8arrays";
44+import { formatDidKey, SECP256K1_JWT_ALG } from "../util/crypto.js";
45import { loginAgent, LoginCredentials } from "./util.js";
5667/** Options for the {@link plcSetupLabeler} function. */
77-export interface PlcSetupLabelerOptions {
88+export interface PlcSetupLabelerOptions extends LoginCredentials {
89 /** The HTTPS URL where the labeler is hosted. */
910 endpoint: string;
1011···1415 */
1516 plcToken: string;
16171717- /** The URL of the PDS where the labeler account is located, if different from bsky.social. */
1818- pds?: string;
1919- /** The DID of the labeler account. */
2020- did: string;
2121- /** The password of the labeler account. Cannot be an app password. */
2222- password: string;
2323-2418 /**
2519 * You may choose to provide your own hex-encoded secp256k1 signing key to use for the labeler.
2620 * Leave this empty to generate a new keypair.
···3125}
32263327/** Options for the {@link plcClearLabeler} function. */
3434-export interface PlcClearLabelerOptions {
2828+export interface PlcClearLabelerOptions extends LoginCredentials {
3529 /**
3630 * The token to use to sign the PLC operation.
3731 * If you don't have a token, first call {@link plcRequestToken} to receive one via email.
3832 */
3933 plcToken: string;
4040-4141- /** The URL of the PDS where the labeler account is located, if different from bsky.social. */
4242- pds?: string;
4343- /** The DID of the labeler account. */
4444- did: string;
4545- /** The password to the labeler account. Cannot be an app password. */
4646- password: string;
4734}
48354936/**
···5845export async function plcSetupLabeler(options: PlcSetupLabelerOptions) {
5946 const { agent } = await loginAgent({
6047 pds: options.pds,
6161- identifier: options.did,
4848+ identifier: options.identifier,
6249 password: options.password,
6350 });
64516565- const keypair = options.privateKey
6666- ? await Secp256k1Keypair.import(options.privateKey)
6767- : await Secp256k1Keypair.create({ exportable: true });
5252+ const privateKey = options.privateKey
5353+ ? options.privateKey instanceof Uint8Array
5454+ ? options.privateKey
5555+ : ui8.fromString(options.privateKey, "hex")
5656+ : k256.utils.randomPrivateKey();
68576969- const keyDid = keypair.did();
5858+ const keyDid = formatDidKey(SECP256K1_JWT_ALG, privateKey);
70597160 const operation: ComAtprotoIdentitySignPlcOperation.Input = {};
7261···114103 });
115104116105 if (!options.privateKey && operation.verificationMethods) {
117117- const privateKey = ui8.toString(await keypair.export(), "hex");
106106+ const privateKeyString = ui8.toString(privateKey, "hex");
118107 console.log(
119108 "This is your labeler's signing key. It will be needed to sign any labels you create.",
120109 "You will not be able to retrieve this key again, so make sure to save it somewhere safe.",
121110 "If you lose this key, you can run this again to generate a new one.",
122111 );
123123- console.log("Signing key:", privateKey);
112112+ console.log("Signing key:", privateKeyString);
124113 }
125114126115 return operation;
···134123export async function plcClearLabeler(options: PlcClearLabelerOptions) {
135124 const { agent } = await loginAgent({
136125 pds: options.pds,
137137- identifier: options.did,
126126+ identifier: options.identifier,
138127 password: options.password,
139128 });
140129
+2
src/scripts/util.ts
···77 identifier: string;
88 /** The account password. */
99 password: string;
1010+ /** The 2FA code, if 2FA is enabled. */
1111+ code?: string;
1012}
11131214let xrpc: XRPC | undefined;
+3-3
src/util/crypto.ts
···99const BASE58_MULTIBASE_PREFIX = "z";
1010const DID_KEY_PREFIX = "did:key:";
11111212-const P256_JWT_ALG = "ES256";
1313-const SECP256K1_JWT_ALG = "ES256K";
1212+export const P256_JWT_ALG = "ES256";
1313+export const SECP256K1_JWT_ALG = "ES256K";
14141515const didToSigningKeyCache = new Map<string, { key: string; expires: number }>();
1616···193193 * @param jwtAlg The JWT algorithm used by the signing key.
194194 * @param keyBytes The bytes of the pubkey.
195195 */
196196-const formatDidKey = (
196196+export const formatDidKey = (
197197 jwtAlg: typeof P256_JWT_ALG | typeof SECP256K1_JWT_ALG,
198198 keyBytes: Uint8Array,
199199): string => DID_KEY_PREFIX + formatMultikey(jwtAlg, keyBytes);