@shin1ohno/sage 0.11.1 → 0.12.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/cli/http-server-with-config.d.ts.map +1 -1
- package/dist/cli/http-server-with-config.js +45 -1
- package/dist/cli/http-server-with-config.js.map +1 -1
- package/dist/cli/mcp-handler.d.ts.map +1 -1
- package/dist/cli/mcp-handler.js +41 -1
- package/dist/cli/mcp-handler.js.map +1 -1
- package/dist/index.js +37 -2
- package/dist/index.js.map +1 -1
- package/dist/integrations/google-calendar-service.d.ts.map +1 -1
- package/dist/integrations/google-calendar-service.js +16 -8
- package/dist/integrations/google-calendar-service.js.map +1 -1
- package/dist/oauth/google-oauth-callback-handler.d.ts +57 -0
- package/dist/oauth/google-oauth-callback-handler.d.ts.map +1 -0
- package/dist/oauth/google-oauth-callback-handler.js +291 -0
- package/dist/oauth/google-oauth-callback-handler.js.map +1 -0
- package/dist/oauth/index.d.ts +2 -0
- package/dist/oauth/index.d.ts.map +1 -1
- package/dist/oauth/index.js +4 -0
- package/dist/oauth/index.js.map +1 -1
- package/dist/oauth/pending-google-auth-store.d.ts +88 -0
- package/dist/oauth/pending-google-auth-store.d.ts.map +1 -0
- package/dist/oauth/pending-google-auth-store.js +218 -0
- package/dist/oauth/pending-google-auth-store.js.map +1 -0
- package/dist/tools/oauth/authenticate-google.d.ts +18 -7
- package/dist/tools/oauth/authenticate-google.d.ts.map +1 -1
- package/dist/tools/oauth/authenticate-google.js +95 -9
- package/dist/tools/oauth/authenticate-google.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pending Google Auth Store
|
|
3
|
+
* Requirements: FR-3 (Pending Auth Session Management)
|
|
4
|
+
*
|
|
5
|
+
* Manages pending Google OAuth authentication sessions for remote mode.
|
|
6
|
+
* Sessions are stored encrypted and expire after a configurable timeout.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Pending Google Auth Session
|
|
10
|
+
*/
|
|
11
|
+
export interface PendingGoogleAuth {
|
|
12
|
+
state: string;
|
|
13
|
+
codeVerifier: string;
|
|
14
|
+
redirectUri: string;
|
|
15
|
+
createdAt: number;
|
|
16
|
+
expiresAt: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Result of creating a new pending auth session
|
|
20
|
+
*/
|
|
21
|
+
export interface CreatePendingAuthResult {
|
|
22
|
+
state: string;
|
|
23
|
+
codeVerifier: string;
|
|
24
|
+
codeChallenge: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Pending Google Auth Store
|
|
28
|
+
*
|
|
29
|
+
* Manages pending OAuth sessions with encrypted persistence.
|
|
30
|
+
*/
|
|
31
|
+
export declare class PendingGoogleAuthStore {
|
|
32
|
+
private sessions;
|
|
33
|
+
private readonly storagePath;
|
|
34
|
+
private readonly encryptionService;
|
|
35
|
+
private readonly sessionTimeoutMs;
|
|
36
|
+
private cleanupTimer;
|
|
37
|
+
private initialized;
|
|
38
|
+
constructor(encryptionKey?: string);
|
|
39
|
+
/**
|
|
40
|
+
* Initialize the store and start cleanup timer
|
|
41
|
+
*/
|
|
42
|
+
initialize(): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Create a new pending auth session
|
|
45
|
+
*
|
|
46
|
+
* @param redirectUri - The OAuth callback URL
|
|
47
|
+
* @returns Session state, code_verifier, and code_challenge
|
|
48
|
+
*/
|
|
49
|
+
create(redirectUri: string): CreatePendingAuthResult;
|
|
50
|
+
/**
|
|
51
|
+
* Find a session by state
|
|
52
|
+
*
|
|
53
|
+
* @param state - The session state (UUID)
|
|
54
|
+
* @returns The session or null if not found/expired
|
|
55
|
+
*/
|
|
56
|
+
findByState(state: string): PendingGoogleAuth | null;
|
|
57
|
+
/**
|
|
58
|
+
* Remove a session by state
|
|
59
|
+
*
|
|
60
|
+
* @param state - The session state to remove
|
|
61
|
+
*/
|
|
62
|
+
remove(state: string): void;
|
|
63
|
+
/**
|
|
64
|
+
* Clean up expired sessions
|
|
65
|
+
*/
|
|
66
|
+
cleanupExpired(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Get session timeout in seconds
|
|
69
|
+
*/
|
|
70
|
+
getSessionTimeoutSeconds(): number;
|
|
71
|
+
/**
|
|
72
|
+
* Persist sessions to encrypted file
|
|
73
|
+
*/
|
|
74
|
+
persist(): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Load sessions from encrypted file
|
|
77
|
+
*/
|
|
78
|
+
load(): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Shutdown the store and stop cleanup timer
|
|
81
|
+
*/
|
|
82
|
+
shutdown(): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Get the number of active sessions
|
|
85
|
+
*/
|
|
86
|
+
getSessionCount(): number;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=pending-google-auth-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-google-auth-store.d.ts","sourceRoot":"","sources":["../../src/oauth/pending-google-auth-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAUD;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAYD;;;;GAIG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAA6C;IAC7D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAoB;IACtD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,WAAW,CAAkB;gBAEzB,aAAa,CAAC,EAAE,MAAM;IAalC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBjC;;;;;OAKG;IACH,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,uBAAuB;IA8BpD;;;;;OAKG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAiBpD;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAa3B;;OAEG;IACH,cAAc,IAAI,IAAI;IAqBtB;;OAEG;IACH,wBAAwB,IAAI,MAAM;IAIlC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB9B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B3B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAY/B;;OAEG;IACH,eAAe,IAAI,MAAM;CAG1B"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pending Google Auth Store
|
|
3
|
+
* Requirements: FR-3 (Pending Auth Session Management)
|
|
4
|
+
*
|
|
5
|
+
* Manages pending Google OAuth authentication sessions for remote mode.
|
|
6
|
+
* Sessions are stored encrypted and expire after a configurable timeout.
|
|
7
|
+
*/
|
|
8
|
+
import { randomUUID } from 'crypto';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { homedir } from 'os';
|
|
11
|
+
import { generateCodeVerifier, generateCodeChallenge } from './pkce.js';
|
|
12
|
+
import { EncryptionService } from './encryption-service.js';
|
|
13
|
+
import { oauthLogger } from '../utils/logger.js';
|
|
14
|
+
/**
|
|
15
|
+
* Default session timeout (10 minutes)
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULT_SESSION_TIMEOUT_MS = 10 * 60 * 1000;
|
|
18
|
+
/**
|
|
19
|
+
* Cleanup interval (5 minutes)
|
|
20
|
+
*/
|
|
21
|
+
const CLEANUP_INTERVAL_MS = 5 * 60 * 1000;
|
|
22
|
+
/**
|
|
23
|
+
* Pending Google Auth Store
|
|
24
|
+
*
|
|
25
|
+
* Manages pending OAuth sessions with encrypted persistence.
|
|
26
|
+
*/
|
|
27
|
+
export class PendingGoogleAuthStore {
|
|
28
|
+
sessions = new Map();
|
|
29
|
+
storagePath;
|
|
30
|
+
encryptionService;
|
|
31
|
+
sessionTimeoutMs;
|
|
32
|
+
cleanupTimer = null;
|
|
33
|
+
initialized = false;
|
|
34
|
+
constructor(encryptionKey) {
|
|
35
|
+
this.storagePath = join(homedir(), '.sage', 'google_pending_auth.enc');
|
|
36
|
+
this.encryptionService = new EncryptionService({
|
|
37
|
+
encryptionKey: encryptionKey || process.env.SAGE_ENCRYPTION_KEY,
|
|
38
|
+
});
|
|
39
|
+
// Parse session timeout from environment or use default
|
|
40
|
+
const timeoutEnv = process.env.GOOGLE_AUTH_SESSION_TIMEOUT;
|
|
41
|
+
this.sessionTimeoutMs = timeoutEnv
|
|
42
|
+
? parseInt(timeoutEnv, 10) * 1000
|
|
43
|
+
: DEFAULT_SESSION_TIMEOUT_MS;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Initialize the store and start cleanup timer
|
|
47
|
+
*/
|
|
48
|
+
async initialize() {
|
|
49
|
+
if (this.initialized) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
await this.encryptionService.initialize();
|
|
53
|
+
await this.load();
|
|
54
|
+
// Start periodic cleanup
|
|
55
|
+
this.cleanupTimer = setInterval(() => {
|
|
56
|
+
this.cleanupExpired();
|
|
57
|
+
}, CLEANUP_INTERVAL_MS);
|
|
58
|
+
// Don't prevent process exit
|
|
59
|
+
this.cleanupTimer.unref();
|
|
60
|
+
this.initialized = true;
|
|
61
|
+
oauthLogger.info('PendingGoogleAuthStore initialized');
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Create a new pending auth session
|
|
65
|
+
*
|
|
66
|
+
* @param redirectUri - The OAuth callback URL
|
|
67
|
+
* @returns Session state, code_verifier, and code_challenge
|
|
68
|
+
*/
|
|
69
|
+
create(redirectUri) {
|
|
70
|
+
const state = randomUUID();
|
|
71
|
+
const codeVerifier = generateCodeVerifier();
|
|
72
|
+
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
const session = {
|
|
75
|
+
state,
|
|
76
|
+
codeVerifier,
|
|
77
|
+
redirectUri,
|
|
78
|
+
createdAt: now,
|
|
79
|
+
expiresAt: now + this.sessionTimeoutMs,
|
|
80
|
+
};
|
|
81
|
+
this.sessions.set(state, session);
|
|
82
|
+
// Persist asynchronously (don't block)
|
|
83
|
+
this.persist().catch(err => {
|
|
84
|
+
oauthLogger.error({ err }, 'Failed to persist pending auth session');
|
|
85
|
+
});
|
|
86
|
+
oauthLogger.info({ state }, 'Created pending auth session');
|
|
87
|
+
return {
|
|
88
|
+
state,
|
|
89
|
+
codeVerifier,
|
|
90
|
+
codeChallenge,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Find a session by state
|
|
95
|
+
*
|
|
96
|
+
* @param state - The session state (UUID)
|
|
97
|
+
* @returns The session or null if not found/expired
|
|
98
|
+
*/
|
|
99
|
+
findByState(state) {
|
|
100
|
+
const session = this.sessions.get(state);
|
|
101
|
+
if (!session) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
// Check expiration
|
|
105
|
+
if (Date.now() > session.expiresAt) {
|
|
106
|
+
this.sessions.delete(state);
|
|
107
|
+
oauthLogger.info({ state }, 'Session expired');
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
return session;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Remove a session by state
|
|
114
|
+
*
|
|
115
|
+
* @param state - The session state to remove
|
|
116
|
+
*/
|
|
117
|
+
remove(state) {
|
|
118
|
+
const existed = this.sessions.delete(state);
|
|
119
|
+
if (existed) {
|
|
120
|
+
oauthLogger.info({ state }, 'Removed pending auth session');
|
|
121
|
+
// Persist asynchronously
|
|
122
|
+
this.persist().catch(err => {
|
|
123
|
+
oauthLogger.error({ err }, 'Failed to persist after session removal');
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Clean up expired sessions
|
|
129
|
+
*/
|
|
130
|
+
cleanupExpired() {
|
|
131
|
+
const now = Date.now();
|
|
132
|
+
let removedCount = 0;
|
|
133
|
+
for (const [state, session] of this.sessions.entries()) {
|
|
134
|
+
if (now > session.expiresAt) {
|
|
135
|
+
this.sessions.delete(state);
|
|
136
|
+
removedCount++;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (removedCount > 0) {
|
|
140
|
+
oauthLogger.info({ removedCount }, 'Cleaned up expired sessions');
|
|
141
|
+
// Persist asynchronously
|
|
142
|
+
this.persist().catch(err => {
|
|
143
|
+
oauthLogger.error({ err }, 'Failed to persist after cleanup');
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get session timeout in seconds
|
|
149
|
+
*/
|
|
150
|
+
getSessionTimeoutSeconds() {
|
|
151
|
+
return Math.floor(this.sessionTimeoutMs / 1000);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Persist sessions to encrypted file
|
|
155
|
+
*/
|
|
156
|
+
async persist() {
|
|
157
|
+
try {
|
|
158
|
+
const storage = {
|
|
159
|
+
version: 1,
|
|
160
|
+
sessions: Array.from(this.sessions.values()),
|
|
161
|
+
};
|
|
162
|
+
await this.encryptionService.encryptToFile(JSON.stringify(storage), this.storagePath);
|
|
163
|
+
oauthLogger.debug({ sessionCount: this.sessions.size }, 'Persisted pending auth sessions');
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
oauthLogger.error({ err: error }, 'Failed to persist pending auth sessions');
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Load sessions from encrypted file
|
|
172
|
+
*/
|
|
173
|
+
async load() {
|
|
174
|
+
try {
|
|
175
|
+
const data = await this.encryptionService.decryptFromFile(this.storagePath);
|
|
176
|
+
if (data === null) {
|
|
177
|
+
oauthLogger.debug('No existing pending auth sessions found');
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const storage = JSON.parse(data);
|
|
181
|
+
if (storage.version !== 1) {
|
|
182
|
+
oauthLogger.warn({ version: storage.version }, 'Unknown storage version, ignoring');
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// Load sessions and filter out expired ones
|
|
186
|
+
const now = Date.now();
|
|
187
|
+
for (const session of storage.sessions) {
|
|
188
|
+
if (now < session.expiresAt) {
|
|
189
|
+
this.sessions.set(session.state, session);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
oauthLogger.info({ sessionCount: this.sessions.size }, 'Loaded pending auth sessions');
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
oauthLogger.error({ err: error }, 'Failed to load pending auth sessions');
|
|
196
|
+
// Don't throw - start with empty sessions
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Shutdown the store and stop cleanup timer
|
|
201
|
+
*/
|
|
202
|
+
async shutdown() {
|
|
203
|
+
if (this.cleanupTimer) {
|
|
204
|
+
clearInterval(this.cleanupTimer);
|
|
205
|
+
this.cleanupTimer = null;
|
|
206
|
+
}
|
|
207
|
+
// Final persist
|
|
208
|
+
await this.persist();
|
|
209
|
+
oauthLogger.info('PendingGoogleAuthStore shutdown');
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Get the number of active sessions
|
|
213
|
+
*/
|
|
214
|
+
getSessionCount() {
|
|
215
|
+
return this.sessions.size;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=pending-google-auth-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-google-auth-store.js","sourceRoot":"","sources":["../../src/oauth/pending-google-auth-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
* Requirements: FR-1 (authenticate_google MCP Tool)
|
|
4
4
|
*
|
|
5
5
|
* Orchestrates the complete Google OAuth flow:
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* 7. Store tokens
|
|
6
|
+
* - Local mode: Start callback server, open browser, wait for callback
|
|
7
|
+
* - Remote mode: Return authorization URL for user to open manually
|
|
8
|
+
*
|
|
9
|
+
* Mode is determined by GOOGLE_REDIRECT_URI:
|
|
10
|
+
* - Contains 'localhost' or '127.0.0.1' -> Local mode
|
|
11
|
+
* - Otherwise -> Remote mode (server receives callback directly)
|
|
13
12
|
*/
|
|
14
13
|
import { z } from 'zod';
|
|
14
|
+
import { PendingGoogleAuthStore } from '../../oauth/pending-google-auth-store.js';
|
|
15
15
|
import type { OAuthToolsContext } from './index.js';
|
|
16
16
|
/**
|
|
17
17
|
* Arguments for authenticate_google tool
|
|
@@ -40,7 +40,18 @@ export interface AuthenticateGoogleResult {
|
|
|
40
40
|
scopes?: string[];
|
|
41
41
|
authorizationUrl?: string;
|
|
42
42
|
error?: string;
|
|
43
|
+
state?: string;
|
|
44
|
+
pendingAuth?: boolean;
|
|
45
|
+
expiresIn?: number;
|
|
43
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Export the pending auth store for use by HTTP server
|
|
49
|
+
*/
|
|
50
|
+
export declare function getSharedPendingAuthStore(): PendingGoogleAuthStore | null;
|
|
51
|
+
/**
|
|
52
|
+
* Set the shared pending auth store (called by HTTP server)
|
|
53
|
+
*/
|
|
54
|
+
export declare function setSharedPendingAuthStore(store: PendingGoogleAuthStore): void;
|
|
44
55
|
/**
|
|
45
56
|
* Handle authenticate_google tool call
|
|
46
57
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate-google.d.ts","sourceRoot":"","sources":["../../../src/tools/oauth/authenticate-google.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"authenticate-google.d.ts","sourceRoot":"","sources":["../../../src/tools/oauth/authenticate-google.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAGlF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;GAEG;AACH,eAAO,MAAM,4BAA4B;IACvC,mDAAmD;;IAEnD,oDAAoD;;;;;;;;EAEpD,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAElF;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkBD;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,sBAAsB,GAAG,IAAI,CAEzE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAE7E;AAkBD;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,sBAAsB,EAC5B,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,wBAAwB,CAAC,CA2KnC"}
|
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
* Requirements: FR-1 (authenticate_google MCP Tool)
|
|
4
4
|
*
|
|
5
5
|
* Orchestrates the complete Google OAuth flow:
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* 7. Store tokens
|
|
6
|
+
* - Local mode: Start callback server, open browser, wait for callback
|
|
7
|
+
* - Remote mode: Return authorization URL for user to open manually
|
|
8
|
+
*
|
|
9
|
+
* Mode is determined by GOOGLE_REDIRECT_URI:
|
|
10
|
+
* - Contains 'localhost' or '127.0.0.1' -> Local mode
|
|
11
|
+
* - Otherwise -> Remote mode (server receives callback directly)
|
|
13
12
|
*/
|
|
14
13
|
import { z } from 'zod';
|
|
15
14
|
import { OAuthCallbackServer } from '../../oauth/oauth-callback-server.js';
|
|
16
|
-
import { GoogleOAuthHandler } from '../../oauth/google-oauth-handler.js';
|
|
15
|
+
import { GoogleOAuthHandler, GOOGLE_CALENDAR_SCOPES } from '../../oauth/google-oauth-handler.js';
|
|
16
|
+
import { PendingGoogleAuthStore } from '../../oauth/pending-google-auth-store.js';
|
|
17
17
|
import { openBrowser } from '../../utils/browser-opener.js';
|
|
18
18
|
import { oauthLogger } from '../../utils/logger.js';
|
|
19
19
|
/**
|
|
@@ -25,6 +25,46 @@ export const AuthenticateGoogleArgsSchema = z.object({
|
|
|
25
25
|
/** Timeout in seconds (default: 300 = 5 minutes) */
|
|
26
26
|
timeout: z.number().optional().default(300),
|
|
27
27
|
});
|
|
28
|
+
/**
|
|
29
|
+
* Singleton instance of PendingGoogleAuthStore for remote mode
|
|
30
|
+
*/
|
|
31
|
+
let pendingAuthStore = null;
|
|
32
|
+
/**
|
|
33
|
+
* Get or create the pending auth store
|
|
34
|
+
*/
|
|
35
|
+
async function getPendingAuthStore() {
|
|
36
|
+
if (!pendingAuthStore) {
|
|
37
|
+
pendingAuthStore = new PendingGoogleAuthStore();
|
|
38
|
+
await pendingAuthStore.initialize();
|
|
39
|
+
}
|
|
40
|
+
return pendingAuthStore;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Export the pending auth store for use by HTTP server
|
|
44
|
+
*/
|
|
45
|
+
export function getSharedPendingAuthStore() {
|
|
46
|
+
return pendingAuthStore;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Set the shared pending auth store (called by HTTP server)
|
|
50
|
+
*/
|
|
51
|
+
export function setSharedPendingAuthStore(store) {
|
|
52
|
+
pendingAuthStore = store;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Check if running in remote mode
|
|
56
|
+
*
|
|
57
|
+
* Remote mode is enabled when GOOGLE_REDIRECT_URI is set and
|
|
58
|
+
* does not point to localhost/127.0.0.1.
|
|
59
|
+
*/
|
|
60
|
+
function isRemoteMode() {
|
|
61
|
+
const redirectUri = process.env.GOOGLE_REDIRECT_URI;
|
|
62
|
+
if (!redirectUri) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
const lowerUri = redirectUri.toLowerCase();
|
|
66
|
+
return !lowerUri.includes('localhost') && !lowerUri.includes('127.0.0.1');
|
|
67
|
+
}
|
|
28
68
|
/**
|
|
29
69
|
* Handle authenticate_google tool call
|
|
30
70
|
*
|
|
@@ -95,7 +135,11 @@ export async function handleAuthenticateGoogle(args, _context) {
|
|
|
95
135
|
oauthLogger.debug({ error }, 'No existing tokens found');
|
|
96
136
|
}
|
|
97
137
|
}
|
|
98
|
-
//
|
|
138
|
+
// Remote mode: return authorization URL for user to open manually
|
|
139
|
+
if (isRemoteMode()) {
|
|
140
|
+
return handleRemoteModeAuth(oauthHandler, redirectUri);
|
|
141
|
+
}
|
|
142
|
+
// Local mode: Start callback server
|
|
99
143
|
const callbackServer = new OAuthCallbackServer({
|
|
100
144
|
timeout: timeout * 1000, // Convert to milliseconds
|
|
101
145
|
});
|
|
@@ -177,4 +221,46 @@ export async function handleAuthenticateGoogle(args, _context) {
|
|
|
177
221
|
await callbackServer.shutdown();
|
|
178
222
|
}
|
|
179
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Handle remote mode authentication
|
|
226
|
+
*
|
|
227
|
+
* In remote mode, we return the authorization URL for the user to open
|
|
228
|
+
* manually in their browser. The server will receive the callback directly.
|
|
229
|
+
*/
|
|
230
|
+
async function handleRemoteModeAuth(_oauthHandler, redirectUri) {
|
|
231
|
+
try {
|
|
232
|
+
const store = await getPendingAuthStore();
|
|
233
|
+
// Create pending auth session (codeVerifier is stored in the session for later use)
|
|
234
|
+
const { state, codeChallenge } = store.create(redirectUri);
|
|
235
|
+
// Generate authorization URL with PKCE
|
|
236
|
+
const { google } = await import('googleapis');
|
|
237
|
+
const oauth2Client = new google.auth.OAuth2(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, redirectUri);
|
|
238
|
+
const authorizationUrl = oauth2Client.generateAuthUrl({
|
|
239
|
+
access_type: 'offline',
|
|
240
|
+
scope: GOOGLE_CALENDAR_SCOPES,
|
|
241
|
+
code_challenge: codeChallenge,
|
|
242
|
+
code_challenge_method: 'S256',
|
|
243
|
+
prompt: 'consent',
|
|
244
|
+
state,
|
|
245
|
+
});
|
|
246
|
+
oauthLogger.info({ state, redirectUri }, 'Generated remote mode authorization URL');
|
|
247
|
+
return {
|
|
248
|
+
success: true,
|
|
249
|
+
message: '以下のURLをブラウザで開いてGoogle認証を完了してください。',
|
|
250
|
+
authorizationUrl,
|
|
251
|
+
state,
|
|
252
|
+
pendingAuth: true,
|
|
253
|
+
expiresIn: store.getSessionTimeoutSeconds(),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
258
|
+
oauthLogger.error({ error }, 'Remote mode auth failed');
|
|
259
|
+
return {
|
|
260
|
+
success: false,
|
|
261
|
+
message: '認証URLの生成に失敗しました。',
|
|
262
|
+
error: errorMessage,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
180
266
|
//# sourceMappingURL=authenticate-google.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate-google.js","sourceRoot":"","sources":["../../../src/tools/oauth/authenticate-google.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"authenticate-google.js","sourceRoot":"","sources":["../../../src/tools/oauth/authenticate-google.ts"],"names":[],"mappings":"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"}
|