@@ -10,6 +10,38 @@ import { handleResolver } from '#server/utils/atproto/oauth'
1010import { type AtIdentifierString , Client } from '@atproto/lex'
1111import * as app from '#shared/types/lexicons/app'
1212
13+ /**
14+ * Fetch the user's profile record to get their avatar blob reference
15+ * @param did
16+ * @param pds
17+ * @returns
18+ */
19+ async function getAvatar ( did : string , pds : string ) {
20+ let avatar : string | undefined
21+ try {
22+ const pdsUrl = new URL ( pds )
23+ // Only fetch from HTTPS PDS endpoints to prevent SSRF
24+ if ( did && pdsUrl . protocol === 'https:' ) {
25+ const client = new Client ( pdsUrl )
26+ const profileResponse = await client . get ( app . bsky . actor . profile , {
27+ // Hack for now need to find an example on how to use it properly
28+ repo : did as AtIdentifierString ,
29+ rkey : 'self' ,
30+ } )
31+
32+ const validatedResponse = app . bsky . actor . profile . main . validate ( profileResponse . value )
33+
34+ if ( validatedResponse . avatar ?. ref ) {
35+ // Use Bluesky CDN for faster image loading
36+ avatar = `https://cdn.bsky.app/img/feed_thumbnail/plain/${ did } /${ validatedResponse . avatar ?. ref } @jpeg`
37+ }
38+ }
39+ } catch {
40+ // Avatar fetch failed, continue without it
41+ }
42+ return avatar
43+ }
44+
1345export default defineEventHandler ( async event => {
1446 const config = useRuntimeConfig ( event )
1547 if ( ! config . sessionPassword ) {
@@ -72,30 +104,7 @@ export default defineEventHandler(async event => {
72104 if ( response . ok ) {
73105 const miniDoc : PublicUserSession = await response . json ( )
74106
75- // Fetch the user's profile record to get their avatar blob reference
76- let avatar : string | undefined
77- const did = agent . did
78- try {
79- const pdsUrl = new URL ( miniDoc . pds )
80- // Only fetch from HTTPS PDS endpoints to prevent SSRF
81- if ( did && pdsUrl . protocol === 'https:' ) {
82- const client = new Client ( pdsUrl )
83- const profileResponse = await client . get ( app . bsky . actor . profile , {
84- // Hack for now need to find an example on how to use it properly
85- repo : did as AtIdentifierString ,
86- rkey : 'self' ,
87- } )
88-
89- const validatedResponse = app . bsky . actor . profile . main . validate ( profileResponse . value )
90-
91- if ( validatedResponse . avatar ?. ref ) {
92- // Use Bluesky CDN for faster image loading
93- avatar = `https://cdn.bsky.app/img/feed_thumbnail/plain/${ did } /${ validatedResponse . avatar ?. ref } @jpeg`
94- }
95- }
96- } catch {
97- // Avatar fetch failed, continue without it
98- }
107+ let avatar : string | undefined = await getAvatar ( authSession . did , miniDoc . pds )
99108
100109 await session . update ( {
101110 public : {
@@ -106,14 +115,15 @@ export default defineEventHandler(async event => {
106115 } else {
107116 //If slingshot fails we still want to set some key info we need.
108117 const pdsBase = ( await authSession . getTokenInfo ( ) ) . aud
118+ let avatar : string | undefined = await getAvatar ( authSession . did , pdsBase )
109119 await session . update ( {
110120 public : {
111121 did : authSession . did ,
112122 handle : 'Not available' ,
113123 pds : pdsBase ,
124+ avatar,
114125 } ,
115126 } )
116127 }
117-
118128 return sendRedirect ( event , '/' )
119129} )
0 commit comments