mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-08-16 14:26:06 +00:00
fix(migrate): oauth account:* spec, p256 support
Lewis: May this revision serve well! <lu5a@proton.me>
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
],
|
||||
"grant_types": ["authorization_code", "refresh_token"],
|
||||
"response_types": ["code"],
|
||||
"scope": "atproto transition:generic repo:* blob:*/* rpc:* rpc:com.atproto.server.createAccount?aud=* account:*?action=manage identity:*",
|
||||
"scope": "atproto transition:generic repo:* blob:*/* rpc:* rpc:com.atproto.server.createAccount?aud=* account:*?action=manage account:repo?action=manage identity:*",
|
||||
"token_endpoint_auth_method": "none",
|
||||
"application_type": "web",
|
||||
"dpop_bound_access_tokens": true
|
||||
|
||||
@@ -209,11 +209,15 @@ export function createOfflineInboundMigrationFlow() {
|
||||
}
|
||||
|
||||
try {
|
||||
userRotationKeypair = await plcOps.getKeyPair(state.rotationKey.trim());
|
||||
const { lastOperation } = await plcOps.getLastPlcOpFromPlc(state.userDid);
|
||||
const currentRotationKeys = lastOperation.rotationKeys || [];
|
||||
|
||||
if (!currentRotationKeys.includes(userRotationKeypair.didPublicKey)) {
|
||||
userRotationKeypair = await plcOps.getMatchingKeyPair(
|
||||
state.rotationKey.trim(),
|
||||
currentRotationKeys,
|
||||
);
|
||||
|
||||
if (!userRotationKeypair) {
|
||||
state.rotationKeyDidKey = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -248,6 +248,33 @@ export class PlcOps {
|
||||
};
|
||||
}
|
||||
|
||||
async getMatchingKeyPair(
|
||||
privateKeyString: string,
|
||||
acceptableDidKeys: readonly string[],
|
||||
): Promise<KeypairInfo | null> {
|
||||
const curves: readonly KeyCurve[] = ["secp256k1", "p256"];
|
||||
const results = await Promise.allSettled(
|
||||
curves.map((curve) => this.getKeyPair(privateKeyString, curve)),
|
||||
);
|
||||
const candidates = results
|
||||
.filter(
|
||||
(r): r is PromiseFulfilledResult<KeypairInfo> =>
|
||||
r.status === "fulfilled",
|
||||
)
|
||||
.map((r) => r.value);
|
||||
if (candidates.length === 0) {
|
||||
const rejection = results.find(
|
||||
(r): r is PromiseRejectedResult => r.status === "rejected",
|
||||
);
|
||||
throw rejection?.reason ?? new Error("Unrecognized key format");
|
||||
}
|
||||
return (
|
||||
candidates.find((info) =>
|
||||
acceptableDidKeys.includes(info.didPublicKey)
|
||||
) ?? null
|
||||
);
|
||||
}
|
||||
|
||||
async signAndPublishNewOp(
|
||||
did: string,
|
||||
signingRotationKey: PrivateKey,
|
||||
|
||||
@@ -144,6 +144,45 @@ describe("migration/plc-ops", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("getMatchingKeyPair", () => {
|
||||
it("resolves a P-256 key supplied as hex against its did:key", async () => {
|
||||
const keypair = await P256PrivateKeyExportable.createKeypair();
|
||||
const rawHex = await keypair.exportPrivateKey("rawHex");
|
||||
const did = await keypair.exportPublicKey("did");
|
||||
|
||||
const result = await plcOps.getMatchingKeyPair(rawHex, [did]);
|
||||
|
||||
expect(result?.didPublicKey).toBe(did);
|
||||
});
|
||||
|
||||
it("resolves a secp256k1 key supplied as hex against its did:key", async () => {
|
||||
const keypair = await Secp256k1PrivateKeyExportable.createKeypair();
|
||||
const rawHex = await keypair.exportPrivateKey("rawHex");
|
||||
const did = await keypair.exportPublicKey("did");
|
||||
|
||||
const result = await plcOps.getMatchingKeyPair(rawHex, [did]);
|
||||
|
||||
expect(result?.didPublicKey).toBe(did);
|
||||
});
|
||||
|
||||
it("returns null when no curve matches the accepted keys", async () => {
|
||||
const keypair = await P256PrivateKeyExportable.createKeypair();
|
||||
const rawHex = await keypair.exportPrivateKey("rawHex");
|
||||
|
||||
const result = await plcOps.getMatchingKeyPair(rawHex, [
|
||||
"did:key:zQ3shqPwo8CSE8zNXEyEpN4ASEBCCNeUFQq8Lrw3zkAJYB7SB",
|
||||
]);
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("throws on unparseable input", async () => {
|
||||
await expect(
|
||||
plcOps.getMatchingKeyPair("not-a-valid-key", []),
|
||||
).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("getKeyPair - JWK format", () => {
|
||||
it("imports secp256k1 JWK with d parameter", async () => {
|
||||
const keypair = await Secp256k1PrivateKeyExportable.createKeypair();
|
||||
|
||||
Reference in New Issue
Block a user