This repository has no description
3.6 kB
106 lines
1import { AtpAgent, Agent } from '@atproto/api';
2import { NodeOAuthClient } from '@atproto/oauth-client-node';
3import { Result, ok, err } from 'src/shared/core/Result';
4import { IAgentService } from '../../application/IAgentService';
5import { DID } from '../../domain/DID';
6import { IAppPasswordSessionService } from '../../application/IAppPasswordSessionService';
7import { ATPROTO_SERVICE_ENDPOINTS } from './ServiceEndpoints';
8import { AuthenticationError } from 'src/shared/core/AuthenticationError';
9
10export class ATProtoAgentService implements IAgentService {
11 constructor(
12 private readonly oauthClient: NodeOAuthClient,
13 private readonly appPasswordSessionService: IAppPasswordSessionService,
14 ) {}
15 getUnauthenticatedAgent(): Result<Agent, Error> {
16 return ok(
17 new Agent({
18 service: ATPROTO_SERVICE_ENDPOINTS.UNAUTHENTICATED_BSKY_SERVICE,
19 }),
20 );
21 }
22 async getAuthenticatedAgent(did: DID): Promise<Result<Agent, Error>> {
23 const oauthAgentResult =
24 await this.getAuthenticatedAgentByOAuthSession(did);
25 if (oauthAgentResult.isErr()) {
26 // If OAuth session fails, try App Password session
27 const appPasswordAgentResult =
28 await this.getAuthenticatedAgentByAppPasswordSession(did);
29 if (appPasswordAgentResult.isErr()) {
30 return err(
31 new AuthenticationError(
32 `Failed to authenticate: No valid OAuth or App Password session found. OAuth error: ${oauthAgentResult.error.message}. App Password error: ${appPasswordAgentResult.error.message}`,
33 ),
34 );
35 }
36 return appPasswordAgentResult;
37 }
38 return oauthAgentResult;
39 }
40 async getAuthenticatedAgentByOAuthSession(
41 did: DID,
42 ): Promise<Result<Agent, Error>> {
43 try {
44 // Try to restore the session for the DID
45 const oauthSession = await this.oauthClient.restore(did.value);
46
47 // If we have a session, create and return an Agent
48 if (oauthSession) {
49 return ok(new Agent(oauthSession));
50 }
51
52 // No session found
53 throw new AuthenticationError(
54 'No OAuth session found for the provided DID',
55 );
56 } catch (error) {
57 return err(
58 new AuthenticationError(
59 `OAuth authentication failed: ${error instanceof Error ? error.message : String(error)}`,
60 ),
61 );
62 }
63 }
64 async getAuthenticatedAgentByAppPasswordSession(
65 did: DID,
66 ): Promise<Result<Agent, Error>> {
67 try {
68 // Try to restore the session for the DID
69 const appPasswordSessionResult =
70 await this.appPasswordSessionService.getSession(did.value);
71
72 if (appPasswordSessionResult.isErr()) {
73 return err(
74 new AuthenticationError(
75 `App Password session failed: ${appPasswordSessionResult.error.message}`,
76 ),
77 );
78 }
79
80 const session = appPasswordSessionResult.value;
81 if (session) {
82 // Create an Agent with the session
83 const agent = new AtpAgent({
84 service: ATPROTO_SERVICE_ENDPOINTS.AUTHENTICATED_BSKY_SERVICE,
85 });
86
87 // Resume the session
88 await agent.resumeSession(session);
89
90 // Return the authenticated agent
91 return ok(agent);
92 }
93
94 // No session found
95 throw new AuthenticationError(
96 'No App Password session found for the provided DID',
97 );
98 } catch (error) {
99 return err(
100 new AuthenticationError(
101 `App Password authentication failed: ${error instanceof Error ? error.message : String(error)}`,
102 ),
103 );
104 }
105 }
106}