A decentralized music tracking and discovery platform built on AT Protocol 🎵

Add password login by resolving PDS from DID

authored by tsiry-sandratraina.com and committed by tangled.org bb3ebf4d 65c1a8bc

+60 -1
+27 -1
apps/api/src/bsky/app.ts
··· 1 + import { AtpAgent } from "@atproto/api"; 1 2 import type { BlobRef } from "@atproto/lexicon"; 2 3 import { isValidHandle } from "@atproto/syntax"; 3 4 import { ctx } from "context"; ··· 8 9 import { deepSnakeCaseKeys } from "lib"; 9 10 import { createAgent } from "lib/agent"; 10 11 import { env } from "lib/env"; 12 + import extractPdsFromDid from "lib/extractPdsFromDid"; 11 13 import { requestCounter } from "metrics"; 12 14 import dropboxAccounts from "schema/dropbox-accounts"; 13 15 import googleDriveAccounts from "schema/google-drive-accounts"; ··· 40 42 41 43 app.post("/login", async (c) => { 42 44 requestCounter.add(1, { method: "POST", route: "/login" }); 43 - const { handle, cli } = await c.req.json(); 45 + const { handle, cli, password } = await c.req.json(); 44 46 if (typeof handle !== "string" || !isValidHandle(handle)) { 45 47 c.status(400); 46 48 return c.text("Invalid handle"); 47 49 } 48 50 49 51 try { 52 + if (password) { 53 + const defaultAgent = new AtpAgent({ 54 + service: new URL("https://bsky.social"), 55 + }); 56 + const { 57 + data: { did }, 58 + } = await defaultAgent.resolveHandle({ handle }); 59 + const pds = await extractPdsFromDid(did); 60 + const agent = new AtpAgent({ 61 + service: new URL(pds), 62 + }); 63 + 64 + const { data } = await agent.login({ 65 + identifier: handle, 66 + password, 67 + }); 68 + 69 + console.log(data); 70 + 71 + console.log("session"); 72 + console.log(agent.session); 73 + 74 + return c.text(data.did); 75 + } 50 76 const url = await ctx.oauthClient.authorize(handle, { 51 77 scope: "atproto transition:generic", 52 78 });
+33
apps/api/src/lib/extractPdsFromDid.ts
··· 1 + export default async function extractPdsFromDid( 2 + did: string, 3 + ): Promise<string | null> { 4 + let didDocUrl: string; 5 + 6 + if (did.startsWith("did:plc:")) { 7 + didDocUrl = `https://plc.directory/${did}`; 8 + } else if (did.startsWith("did:web:")) { 9 + const domain = did.substring("did:web:".length); 10 + didDocUrl = `https://${domain}/.well-known/did.json`; 11 + } else { 12 + throw new Error("Unsupported DID method"); 13 + } 14 + 15 + const response = await fetch(didDocUrl); 16 + if (!response.ok) throw new Error("Failed to fetch DID doc"); 17 + 18 + const doc: { 19 + service?: Array<{ 20 + type: string; 21 + id: string; 22 + serviceEndpoint: string; 23 + }>; 24 + } = await response.json(); 25 + 26 + // Find the atproto PDS service 27 + const pdsService = doc.service?.find( 28 + (s: any) => 29 + s.type === "AtprotoPersonalDataServer" && s.id.endsWith("#atproto_pds"), 30 + ); 31 + 32 + return pdsService?.serviceEndpoint ?? null; 33 + }