@chrishdx/llm-dev-server 1.0.0
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/LICENSE +21 -0
- package/README.md +164 -0
- package/backend/bin/llm-dev-server.js +3 -0
- package/backend/dist/cli.d.ts +15 -0
- package/backend/dist/cli.d.ts.map +1 -0
- package/backend/dist/cli.js +326 -0
- package/backend/dist/cli.js.map +1 -0
- package/backend/dist/config/database.d.ts +10 -0
- package/backend/dist/config/database.d.ts.map +1 -0
- package/backend/dist/config/database.js +61 -0
- package/backend/dist/config/database.js.map +1 -0
- package/backend/dist/config/environment.d.ts +20 -0
- package/backend/dist/config/environment.d.ts.map +1 -0
- package/backend/dist/config/environment.js +77 -0
- package/backend/dist/config/environment.js.map +1 -0
- package/backend/dist/controllers/AuthController.d.ts +18 -0
- package/backend/dist/controllers/AuthController.d.ts.map +1 -0
- package/backend/dist/controllers/AuthController.js +282 -0
- package/backend/dist/controllers/AuthController.js.map +1 -0
- package/backend/dist/controllers/ConversationController.d.ts +44 -0
- package/backend/dist/controllers/ConversationController.d.ts.map +1 -0
- package/backend/dist/controllers/ConversationController.js +193 -0
- package/backend/dist/controllers/ConversationController.js.map +1 -0
- package/backend/dist/controllers/JobController.d.ts +49 -0
- package/backend/dist/controllers/JobController.d.ts.map +1 -0
- package/backend/dist/controllers/JobController.js +227 -0
- package/backend/dist/controllers/JobController.js.map +1 -0
- package/backend/dist/index.d.ts +2 -0
- package/backend/dist/index.d.ts.map +1 -0
- package/backend/dist/index.js +160 -0
- package/backend/dist/index.js.map +1 -0
- package/backend/dist/middleware/auth.middleware.d.ts +25 -0
- package/backend/dist/middleware/auth.middleware.d.ts.map +1 -0
- package/backend/dist/middleware/auth.middleware.js +116 -0
- package/backend/dist/middleware/auth.middleware.js.map +1 -0
- package/backend/dist/middleware/authelia.middleware.d.ts +26 -0
- package/backend/dist/middleware/authelia.middleware.d.ts.map +1 -0
- package/backend/dist/middleware/authelia.middleware.js +165 -0
- package/backend/dist/middleware/authelia.middleware.js.map +1 -0
- package/backend/dist/middleware/error.middleware.d.ts +23 -0
- package/backend/dist/middleware/error.middleware.d.ts.map +1 -0
- package/backend/dist/middleware/error.middleware.js +59 -0
- package/backend/dist/middleware/error.middleware.js.map +1 -0
- package/backend/dist/models/AuthToken.d.ts +42 -0
- package/backend/dist/models/AuthToken.d.ts.map +1 -0
- package/backend/dist/models/AuthToken.js +97 -0
- package/backend/dist/models/AuthToken.js.map +1 -0
- package/backend/dist/models/Conversation.d.ts +36 -0
- package/backend/dist/models/Conversation.d.ts.map +1 -0
- package/backend/dist/models/Conversation.js +100 -0
- package/backend/dist/models/Conversation.js.map +1 -0
- package/backend/dist/models/FileOperation.d.ts +36 -0
- package/backend/dist/models/FileOperation.d.ts.map +1 -0
- package/backend/dist/models/FileOperation.js +117 -0
- package/backend/dist/models/FileOperation.js.map +1 -0
- package/backend/dist/models/Job.d.ts +48 -0
- package/backend/dist/models/Job.d.ts.map +1 -0
- package/backend/dist/models/Job.js +87 -0
- package/backend/dist/models/Job.js.map +1 -0
- package/backend/dist/models/Message.d.ts +38 -0
- package/backend/dist/models/Message.d.ts.map +1 -0
- package/backend/dist/models/Message.js +87 -0
- package/backend/dist/models/Message.js.map +1 -0
- package/backend/dist/models/User.d.ts +26 -0
- package/backend/dist/models/User.d.ts.map +1 -0
- package/backend/dist/models/User.js +67 -0
- package/backend/dist/models/User.js.map +1 -0
- package/backend/dist/models/index.d.ts +13 -0
- package/backend/dist/models/index.d.ts.map +1 -0
- package/backend/dist/models/index.js +24 -0
- package/backend/dist/models/index.js.map +1 -0
- package/backend/dist/routes/auth.routes.d.ts +3 -0
- package/backend/dist/routes/auth.routes.d.ts.map +1 -0
- package/backend/dist/routes/auth.routes.js +27 -0
- package/backend/dist/routes/auth.routes.js.map +1 -0
- package/backend/dist/routes/conversation.routes.d.ts +3 -0
- package/backend/dist/routes/conversation.routes.d.ts.map +1 -0
- package/backend/dist/routes/conversation.routes.js +17 -0
- package/backend/dist/routes/conversation.routes.js.map +1 -0
- package/backend/dist/routes/filesystem.routes.d.ts +3 -0
- package/backend/dist/routes/filesystem.routes.d.ts.map +1 -0
- package/backend/dist/routes/filesystem.routes.js +64 -0
- package/backend/dist/routes/filesystem.routes.js.map +1 -0
- package/backend/dist/routes/index.d.ts +3 -0
- package/backend/dist/routes/index.d.ts.map +1 -0
- package/backend/dist/routes/index.js +27 -0
- package/backend/dist/routes/index.js.map +1 -0
- package/backend/dist/routes/job.routes.d.ts +3 -0
- package/backend/dist/routes/job.routes.d.ts.map +1 -0
- package/backend/dist/routes/job.routes.js +18 -0
- package/backend/dist/routes/job.routes.js.map +1 -0
- package/backend/dist/services/auth/BaseAuthService.d.ts +49 -0
- package/backend/dist/services/auth/BaseAuthService.d.ts.map +1 -0
- package/backend/dist/services/auth/BaseAuthService.js +97 -0
- package/backend/dist/services/auth/BaseAuthService.js.map +1 -0
- package/backend/dist/services/auth/ClaudeAuthService.d.ts +69 -0
- package/backend/dist/services/auth/ClaudeAuthService.d.ts.map +1 -0
- package/backend/dist/services/auth/ClaudeAuthService.js +401 -0
- package/backend/dist/services/auth/ClaudeAuthService.js.map +1 -0
- package/backend/dist/services/auth/CodexAuthService.d.ts +37 -0
- package/backend/dist/services/auth/CodexAuthService.d.ts.map +1 -0
- package/backend/dist/services/auth/CodexAuthService.js +186 -0
- package/backend/dist/services/auth/CodexAuthService.js.map +1 -0
- package/backend/dist/services/auth/GeminiAuthService.d.ts +50 -0
- package/backend/dist/services/auth/GeminiAuthService.d.ts.map +1 -0
- package/backend/dist/services/auth/GeminiAuthService.js +284 -0
- package/backend/dist/services/auth/GeminiAuthService.js.map +1 -0
- package/backend/dist/services/auth/JwtService.d.ts +27 -0
- package/backend/dist/services/auth/JwtService.d.ts.map +1 -0
- package/backend/dist/services/auth/JwtService.js +65 -0
- package/backend/dist/services/auth/JwtService.js.map +1 -0
- package/backend/dist/services/auth/TokenRefreshService.d.ts +36 -0
- package/backend/dist/services/auth/TokenRefreshService.d.ts.map +1 -0
- package/backend/dist/services/auth/TokenRefreshService.js +178 -0
- package/backend/dist/services/auth/TokenRefreshService.js.map +1 -0
- package/backend/dist/services/conversation/ConversationService.d.ts +89 -0
- package/backend/dist/services/conversation/ConversationService.d.ts.map +1 -0
- package/backend/dist/services/conversation/ConversationService.js +255 -0
- package/backend/dist/services/conversation/ConversationService.js.map +1 -0
- package/backend/dist/services/job/JobService.d.ts +83 -0
- package/backend/dist/services/job/JobService.d.ts.map +1 -0
- package/backend/dist/services/job/JobService.js +213 -0
- package/backend/dist/services/job/JobService.js.map +1 -0
- package/backend/dist/services/job/WorkingDirectoryService.d.ts +73 -0
- package/backend/dist/services/job/WorkingDirectoryService.d.ts.map +1 -0
- package/backend/dist/services/job/WorkingDirectoryService.js +289 -0
- package/backend/dist/services/job/WorkingDirectoryService.js.map +1 -0
- package/backend/dist/services/llm/ClaudeProvider.d.ts +16 -0
- package/backend/dist/services/llm/ClaudeProvider.d.ts.map +1 -0
- package/backend/dist/services/llm/ClaudeProvider.js +229 -0
- package/backend/dist/services/llm/ClaudeProvider.js.map +1 -0
- package/backend/dist/services/llm/CodexProvider.d.ts +15 -0
- package/backend/dist/services/llm/CodexProvider.d.ts.map +1 -0
- package/backend/dist/services/llm/CodexProvider.js +301 -0
- package/backend/dist/services/llm/CodexProvider.js.map +1 -0
- package/backend/dist/services/llm/GeminiProvider.d.ts +17 -0
- package/backend/dist/services/llm/GeminiProvider.d.ts.map +1 -0
- package/backend/dist/services/llm/GeminiProvider.js +190 -0
- package/backend/dist/services/llm/GeminiProvider.js.map +1 -0
- package/backend/dist/services/llm/LLMProviderBase.d.ts +76 -0
- package/backend/dist/services/llm/LLMProviderBase.d.ts.map +1 -0
- package/backend/dist/services/llm/LLMProviderBase.js +34 -0
- package/backend/dist/services/llm/LLMProviderBase.js.map +1 -0
- package/backend/dist/services/llm/ProviderFactory.d.ts +17 -0
- package/backend/dist/services/llm/ProviderFactory.d.ts.map +1 -0
- package/backend/dist/services/llm/ProviderFactory.js +58 -0
- package/backend/dist/services/llm/ProviderFactory.js.map +1 -0
- package/backend/dist/utils/crypto.d.ts +33 -0
- package/backend/dist/utils/crypto.d.ts.map +1 -0
- package/backend/dist/utils/crypto.js +165 -0
- package/backend/dist/utils/crypto.js.map +1 -0
- package/backend/dist/utils/logger.d.ts +4 -0
- package/backend/dist/utils/logger.d.ts.map +1 -0
- package/backend/dist/utils/logger.js +44 -0
- package/backend/dist/utils/logger.js.map +1 -0
- package/backend/dist/utils/validators.d.ts +22 -0
- package/backend/dist/utils/validators.d.ts.map +1 -0
- package/backend/dist/utils/validators.js +127 -0
- package/backend/dist/utils/validators.js.map +1 -0
- package/backend/package.json +45 -0
- package/backend/public/assets/index-C207-KqP.js +188 -0
- package/backend/public/index.html +12 -0
- package/package.json +96 -0
- package/shared/dist/index.d.ts +5 -0
- package/shared/dist/index.d.ts.map +1 -0
- package/shared/dist/index.js +25 -0
- package/shared/dist/index.js.map +1 -0
- package/shared/dist/types/api.d.ts +27 -0
- package/shared/dist/types/api.d.ts.map +1 -0
- package/shared/dist/types/api.js +3 -0
- package/shared/dist/types/api.js.map +1 -0
- package/shared/dist/types/auth.d.ts +62 -0
- package/shared/dist/types/auth.d.ts.map +1 -0
- package/shared/dist/types/auth.js +3 -0
- package/shared/dist/types/auth.js.map +1 -0
- package/shared/dist/types/conversation.d.ts +98 -0
- package/shared/dist/types/conversation.d.ts.map +1 -0
- package/shared/dist/types/conversation.js +3 -0
- package/shared/dist/types/conversation.js.map +1 -0
- package/shared/dist/types/job.d.ts +93 -0
- package/shared/dist/types/job.d.ts.map +1 -0
- package/shared/dist/types/job.js +3 -0
- package/shared/dist/types/job.js.map +1 -0
- package/shared/package.json +15 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { BaseAuthService } from './BaseAuthService';
|
|
2
|
+
import { AuthToken } from '../../models';
|
|
3
|
+
export declare class GeminiAuthService extends BaseAuthService {
|
|
4
|
+
private geminiHome;
|
|
5
|
+
constructor();
|
|
6
|
+
/**
|
|
7
|
+
* Start Gemini OAuth login flow
|
|
8
|
+
*/
|
|
9
|
+
startLogin(): Promise<{
|
|
10
|
+
loginUrl: string;
|
|
11
|
+
sessionId: string;
|
|
12
|
+
state: string;
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Complete Gemini OAuth login flow
|
|
16
|
+
*/
|
|
17
|
+
completeLogin(params: {
|
|
18
|
+
sessionId: string;
|
|
19
|
+
code: string;
|
|
20
|
+
state: string;
|
|
21
|
+
}): Promise<AuthToken>;
|
|
22
|
+
/**
|
|
23
|
+
* Load credentials from file on server startup
|
|
24
|
+
*/
|
|
25
|
+
loadFromFile(): Promise<AuthToken | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Get current authentication status
|
|
28
|
+
*/
|
|
29
|
+
getStatus(): Promise<{
|
|
30
|
+
loggedIn: boolean;
|
|
31
|
+
tokenId?: string;
|
|
32
|
+
email?: string;
|
|
33
|
+
expiresAt?: Date;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Start Gemini OAuth login flow with manual code redirect (for remote clients)
|
|
37
|
+
* Uses Google's special redirect URI that displays the code to the user
|
|
38
|
+
*/
|
|
39
|
+
startLoginWithRedirect(_redirectUri: string): Promise<{
|
|
40
|
+
loginUrl: string;
|
|
41
|
+
state: string;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* Complete Gemini OAuth login from manual code (for remote clients)
|
|
45
|
+
* User provides the authorization code shown by Google
|
|
46
|
+
*/
|
|
47
|
+
completeLoginFromCallback(code: string, state: string): Promise<AuthToken>;
|
|
48
|
+
}
|
|
49
|
+
export default GeminiAuthService;
|
|
50
|
+
//# sourceMappingURL=GeminiAuthService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GeminiAuthService.d.ts","sourceRoot":"","sources":["../../../src/services/auth/GeminiAuthService.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAazC,qBAAa,iBAAkB,SAAQ,eAAe;IACpD,OAAO,CAAC,UAAU,CAAS;;IAO3B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC;QAC1B,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IAwCF;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,SAAS,CAAC;IAoFtB;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IA0C/C;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC;QACzB,QAAQ,EAAE,OAAO,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,IAAI,CAAC;KAClB,CAAC;IAeF;;;OAGG;IACG,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAC1D,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IAwCF;;;OAGG;IACG,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;CAmFjF;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.GeminiAuthService = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
+
const google_auth_library_1 = require("google-auth-library");
|
|
11
|
+
const BaseAuthService_1 = require("./BaseAuthService");
|
|
12
|
+
const models_1 = require("../../models");
|
|
13
|
+
const crypto_2 = require("../../utils/crypto");
|
|
14
|
+
const environment_1 = __importDefault(require("../../config/environment"));
|
|
15
|
+
const logger_1 = __importDefault(require("../../utils/logger"));
|
|
16
|
+
const GEMINI_CLIENT_ID = '681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com';
|
|
17
|
+
const GEMINI_CLIENT_SECRET = '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';
|
|
18
|
+
const GEMINI_SCOPES = [
|
|
19
|
+
'https://www.googleapis.com/auth/cloud-platform',
|
|
20
|
+
'https://www.googleapis.com/auth/userinfo.email',
|
|
21
|
+
];
|
|
22
|
+
class GeminiAuthService extends BaseAuthService_1.BaseAuthService {
|
|
23
|
+
constructor() {
|
|
24
|
+
super('gemini');
|
|
25
|
+
this.geminiHome = path_1.default.join(environment_1.default.DATA_DIR, 'gemini');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Start Gemini OAuth login flow
|
|
29
|
+
*/
|
|
30
|
+
async startLogin() {
|
|
31
|
+
const codeVerifier = (0, crypto_2.generateCodeVerifier)();
|
|
32
|
+
const codeChallenge = (0, crypto_2.generateCodeChallenge)(codeVerifier);
|
|
33
|
+
const state = crypto_1.default.randomUUID();
|
|
34
|
+
const redirectUri = 'http://localhost:3000/oauth/callback';
|
|
35
|
+
const oauth2Client = new google_auth_library_1.OAuth2Client({
|
|
36
|
+
clientId: GEMINI_CLIENT_ID,
|
|
37
|
+
clientSecret: GEMINI_CLIENT_SECRET,
|
|
38
|
+
redirectUri,
|
|
39
|
+
});
|
|
40
|
+
const authorizeUrl = oauth2Client.generateAuthUrl({
|
|
41
|
+
access_type: 'offline',
|
|
42
|
+
scope: GEMINI_SCOPES,
|
|
43
|
+
state,
|
|
44
|
+
code_challenge: codeChallenge,
|
|
45
|
+
code_challenge_method: google_auth_library_1.CodeChallengeMethod.S256,
|
|
46
|
+
});
|
|
47
|
+
const sessionId = crypto_1.default.randomUUID();
|
|
48
|
+
await this.storeLoginSession({
|
|
49
|
+
sessionId,
|
|
50
|
+
state,
|
|
51
|
+
codeVerifier: this.encrypt(codeVerifier),
|
|
52
|
+
provider: 'gemini',
|
|
53
|
+
redirectUri,
|
|
54
|
+
expiresAt: new Date(Date.now() + 15 * 60 * 1000),
|
|
55
|
+
});
|
|
56
|
+
logger_1.default.info('Gemini OAuth login started', { sessionId });
|
|
57
|
+
return {
|
|
58
|
+
loginUrl: authorizeUrl,
|
|
59
|
+
sessionId,
|
|
60
|
+
state,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Complete Gemini OAuth login flow
|
|
65
|
+
*/
|
|
66
|
+
async completeLogin(params) {
|
|
67
|
+
// Validate session
|
|
68
|
+
const session = await this.getLoginSession(params.sessionId);
|
|
69
|
+
if (!session || session.state !== params.state) {
|
|
70
|
+
throw new Error('Invalid OAuth state');
|
|
71
|
+
}
|
|
72
|
+
const codeVerifier = this.decrypt(session.codeVerifier);
|
|
73
|
+
const oauth2Client = new google_auth_library_1.OAuth2Client({
|
|
74
|
+
clientId: GEMINI_CLIENT_ID,
|
|
75
|
+
clientSecret: GEMINI_CLIENT_SECRET,
|
|
76
|
+
redirectUri: session.redirectUri || 'http://localhost:3000/oauth/callback',
|
|
77
|
+
});
|
|
78
|
+
// Exchange code for tokens
|
|
79
|
+
const { tokens } = await oauth2Client.getToken({
|
|
80
|
+
code: params.code,
|
|
81
|
+
codeVerifier,
|
|
82
|
+
});
|
|
83
|
+
// Fetch user info
|
|
84
|
+
oauth2Client.setCredentials(tokens);
|
|
85
|
+
const userInfo = await oauth2Client.request({
|
|
86
|
+
url: 'https://www.googleapis.com/oauth2/v2/userinfo',
|
|
87
|
+
});
|
|
88
|
+
const email = userInfo.data.email;
|
|
89
|
+
// 1. Create directory structure
|
|
90
|
+
await promises_1.default.mkdir(this.geminiHome, { recursive: true, mode: 0o700 });
|
|
91
|
+
// 2. Write oauth_creds.json (like native Gemini CLI)
|
|
92
|
+
const credsPath = path_1.default.join(this.geminiHome, 'oauth_creds.json');
|
|
93
|
+
const credsData = {
|
|
94
|
+
type: 'authorized_user',
|
|
95
|
+
client_id: GEMINI_CLIENT_ID,
|
|
96
|
+
client_secret: GEMINI_CLIENT_SECRET,
|
|
97
|
+
refresh_token: tokens.refresh_token,
|
|
98
|
+
token: tokens.access_token,
|
|
99
|
+
expiry_date: tokens.expiry_date,
|
|
100
|
+
};
|
|
101
|
+
await promises_1.default.writeFile(credsPath, JSON.stringify(credsData, null, 2), { encoding: 'utf8', mode: 0o600 });
|
|
102
|
+
// 3. Write google_accounts.json
|
|
103
|
+
const accountsPath = path_1.default.join(this.geminiHome, 'google_accounts.json');
|
|
104
|
+
const accountsData = {
|
|
105
|
+
active_account: email,
|
|
106
|
+
};
|
|
107
|
+
await promises_1.default.writeFile(accountsPath, JSON.stringify(accountsData, null, 2), { encoding: 'utf8', mode: 0o600 });
|
|
108
|
+
logger_1.default.info('Gemini credentials written to file');
|
|
109
|
+
// 4. Store in database
|
|
110
|
+
const authToken = await models_1.AuthToken.create({
|
|
111
|
+
provider: 'gemini',
|
|
112
|
+
accessToken: this.encrypt(tokens.access_token),
|
|
113
|
+
refreshToken: tokens.refresh_token ? this.encrypt(tokens.refresh_token) : undefined,
|
|
114
|
+
tokenType: tokens.token_type || 'Bearer',
|
|
115
|
+
expiresAt: tokens.expiry_date ? new Date(tokens.expiry_date) : undefined,
|
|
116
|
+
issuedAt: new Date(),
|
|
117
|
+
scopes: tokens.scope?.split(' '),
|
|
118
|
+
email,
|
|
119
|
+
isActive: true,
|
|
120
|
+
});
|
|
121
|
+
// Cleanup session
|
|
122
|
+
await this.deleteLoginSession(params.sessionId);
|
|
123
|
+
logger_1.default.info('Gemini OAuth login completed', { tokenId: authToken.id });
|
|
124
|
+
return authToken;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Load credentials from file on server startup
|
|
128
|
+
*/
|
|
129
|
+
async loadFromFile() {
|
|
130
|
+
const credsPath = path_1.default.join(this.geminiHome, 'oauth_creds.json');
|
|
131
|
+
try {
|
|
132
|
+
const content = await promises_1.default.readFile(credsPath, 'utf8');
|
|
133
|
+
const creds = JSON.parse(content);
|
|
134
|
+
// Check if already in database
|
|
135
|
+
let authToken = await models_1.AuthToken.findOne({
|
|
136
|
+
where: { provider: 'gemini', isActive: true },
|
|
137
|
+
});
|
|
138
|
+
if (!authToken) {
|
|
139
|
+
// Read email from google_accounts.json
|
|
140
|
+
const accountsPath = path_1.default.join(this.geminiHome, 'google_accounts.json');
|
|
141
|
+
const accountsContent = await promises_1.default.readFile(accountsPath, 'utf8');
|
|
142
|
+
const accounts = JSON.parse(accountsContent);
|
|
143
|
+
// Create from file
|
|
144
|
+
authToken = await models_1.AuthToken.create({
|
|
145
|
+
provider: 'gemini',
|
|
146
|
+
accessToken: this.encrypt(creds.token),
|
|
147
|
+
refreshToken: creds.refresh_token ? this.encrypt(creds.refresh_token) : undefined,
|
|
148
|
+
tokenType: 'Bearer',
|
|
149
|
+
expiresAt: creds.expiry_date ? new Date(creds.expiry_date) : undefined,
|
|
150
|
+
issuedAt: new Date(),
|
|
151
|
+
email: accounts.active_account,
|
|
152
|
+
isActive: true,
|
|
153
|
+
});
|
|
154
|
+
logger_1.default.info('Gemini credentials loaded from file and synced to database');
|
|
155
|
+
}
|
|
156
|
+
return authToken;
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (error instanceof Error && error.code !== 'ENOENT') {
|
|
160
|
+
logger_1.default.warn('Failed to load Gemini credentials from file:', error.message);
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get current authentication status
|
|
167
|
+
*/
|
|
168
|
+
async getStatus() {
|
|
169
|
+
const token = await this.getActiveToken();
|
|
170
|
+
if (!token) {
|
|
171
|
+
return { loggedIn: false };
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
loggedIn: true,
|
|
175
|
+
tokenId: token.id,
|
|
176
|
+
email: token.email,
|
|
177
|
+
expiresAt: token.expiresAt,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Start Gemini OAuth login flow with manual code redirect (for remote clients)
|
|
182
|
+
* Uses Google's special redirect URI that displays the code to the user
|
|
183
|
+
*/
|
|
184
|
+
async startLoginWithRedirect(_redirectUri) {
|
|
185
|
+
// Use Google's special manual code redirect URI
|
|
186
|
+
const manualRedirectUri = 'https://codeassist.google.com/authcode';
|
|
187
|
+
const codeVerifier = (0, crypto_2.generateCodeVerifier)();
|
|
188
|
+
const codeChallenge = (0, crypto_2.generateCodeChallenge)(codeVerifier);
|
|
189
|
+
const state = crypto_1.default.randomUUID();
|
|
190
|
+
const oauth2Client = new google_auth_library_1.OAuth2Client({
|
|
191
|
+
clientId: GEMINI_CLIENT_ID,
|
|
192
|
+
clientSecret: GEMINI_CLIENT_SECRET,
|
|
193
|
+
redirectUri: manualRedirectUri,
|
|
194
|
+
});
|
|
195
|
+
const authorizeUrl = oauth2Client.generateAuthUrl({
|
|
196
|
+
access_type: 'offline',
|
|
197
|
+
scope: GEMINI_SCOPES,
|
|
198
|
+
state,
|
|
199
|
+
code_challenge: codeChallenge,
|
|
200
|
+
code_challenge_method: google_auth_library_1.CodeChallengeMethod.S256,
|
|
201
|
+
});
|
|
202
|
+
// Store session with state as sessionId for retrieval
|
|
203
|
+
await this.storeLoginSession({
|
|
204
|
+
sessionId: state,
|
|
205
|
+
state,
|
|
206
|
+
codeVerifier: this.encrypt(codeVerifier),
|
|
207
|
+
provider: 'gemini',
|
|
208
|
+
redirectUri: manualRedirectUri,
|
|
209
|
+
expiresAt: new Date(Date.now() + 15 * 60 * 1000),
|
|
210
|
+
});
|
|
211
|
+
logger_1.default.info('Gemini OAuth manual code flow started', { state });
|
|
212
|
+
return {
|
|
213
|
+
loginUrl: authorizeUrl,
|
|
214
|
+
state,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Complete Gemini OAuth login from manual code (for remote clients)
|
|
219
|
+
* User provides the authorization code shown by Google
|
|
220
|
+
*/
|
|
221
|
+
async completeLoginFromCallback(code, state) {
|
|
222
|
+
// Validate session
|
|
223
|
+
const session = await this.getLoginSession(state);
|
|
224
|
+
if (!session || session.state !== state) {
|
|
225
|
+
throw new Error('Invalid OAuth state');
|
|
226
|
+
}
|
|
227
|
+
const codeVerifier = this.decrypt(session.codeVerifier);
|
|
228
|
+
const oauth2Client = new google_auth_library_1.OAuth2Client({
|
|
229
|
+
clientId: GEMINI_CLIENT_ID,
|
|
230
|
+
clientSecret: GEMINI_CLIENT_SECRET,
|
|
231
|
+
redirectUri: session.redirectUri || 'https://codeassist.google.com/authcode',
|
|
232
|
+
});
|
|
233
|
+
// Exchange code for tokens
|
|
234
|
+
const { tokens } = await oauth2Client.getToken({
|
|
235
|
+
code,
|
|
236
|
+
codeVerifier,
|
|
237
|
+
});
|
|
238
|
+
// Fetch user info
|
|
239
|
+
oauth2Client.setCredentials(tokens);
|
|
240
|
+
const userInfo = await oauth2Client.request({
|
|
241
|
+
url: 'https://www.googleapis.com/oauth2/v2/userinfo',
|
|
242
|
+
});
|
|
243
|
+
const email = userInfo.data.email;
|
|
244
|
+
// 1. Create directory structure
|
|
245
|
+
await promises_1.default.mkdir(this.geminiHome, { recursive: true, mode: 0o700 });
|
|
246
|
+
// 2. Write oauth_creds.json (like native Gemini CLI)
|
|
247
|
+
const credsPath = path_1.default.join(this.geminiHome, 'oauth_creds.json');
|
|
248
|
+
const credsData = {
|
|
249
|
+
type: 'authorized_user',
|
|
250
|
+
client_id: GEMINI_CLIENT_ID,
|
|
251
|
+
client_secret: GEMINI_CLIENT_SECRET,
|
|
252
|
+
refresh_token: tokens.refresh_token,
|
|
253
|
+
token: tokens.access_token,
|
|
254
|
+
expiry_date: tokens.expiry_date,
|
|
255
|
+
};
|
|
256
|
+
await promises_1.default.writeFile(credsPath, JSON.stringify(credsData, null, 2), { encoding: 'utf8', mode: 0o600 });
|
|
257
|
+
// 3. Write google_accounts.json
|
|
258
|
+
const accountsPath = path_1.default.join(this.geminiHome, 'google_accounts.json');
|
|
259
|
+
const accountsData = {
|
|
260
|
+
active_account: email,
|
|
261
|
+
};
|
|
262
|
+
await promises_1.default.writeFile(accountsPath, JSON.stringify(accountsData, null, 2), { encoding: 'utf8', mode: 0o600 });
|
|
263
|
+
logger_1.default.info('Gemini credentials written to file');
|
|
264
|
+
// 4. Store in database
|
|
265
|
+
const authToken = await models_1.AuthToken.create({
|
|
266
|
+
provider: 'gemini',
|
|
267
|
+
accessToken: this.encrypt(tokens.access_token),
|
|
268
|
+
refreshToken: tokens.refresh_token ? this.encrypt(tokens.refresh_token) : undefined,
|
|
269
|
+
tokenType: tokens.token_type || 'Bearer',
|
|
270
|
+
expiresAt: tokens.expiry_date ? new Date(tokens.expiry_date) : undefined,
|
|
271
|
+
issuedAt: new Date(),
|
|
272
|
+
scopes: tokens.scope?.split(' '),
|
|
273
|
+
email,
|
|
274
|
+
isActive: true,
|
|
275
|
+
});
|
|
276
|
+
// Cleanup session
|
|
277
|
+
await this.deleteLoginSession(state);
|
|
278
|
+
logger_1.default.info('Gemini OAuth manual code flow completed', { tokenId: authToken.id });
|
|
279
|
+
return authToken;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
exports.GeminiAuthService = GeminiAuthService;
|
|
283
|
+
exports.default = GeminiAuthService;
|
|
284
|
+
//# sourceMappingURL=GeminiAuthService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GeminiAuthService.js","sourceRoot":"","sources":["../../../src/services/auth/GeminiAuthService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { User } from '../../models';
|
|
2
|
+
export interface JwtPayload {
|
|
3
|
+
userId: string;
|
|
4
|
+
username: string;
|
|
5
|
+
role: 'admin' | 'user';
|
|
6
|
+
}
|
|
7
|
+
export declare class JwtService {
|
|
8
|
+
private static readonly EXPIRES_IN;
|
|
9
|
+
/**
|
|
10
|
+
* Generate JWT token for a user
|
|
11
|
+
*/
|
|
12
|
+
static generateToken(user: User): string;
|
|
13
|
+
/**
|
|
14
|
+
* Verify and decode JWT token
|
|
15
|
+
*/
|
|
16
|
+
static verifyToken(token: string): JwtPayload;
|
|
17
|
+
/**
|
|
18
|
+
* Decode token without verification (for debugging)
|
|
19
|
+
*/
|
|
20
|
+
static decodeToken(token: string): JwtPayload | null;
|
|
21
|
+
/**
|
|
22
|
+
* Get token expiration time in seconds
|
|
23
|
+
*/
|
|
24
|
+
static getExpiresIn(): number;
|
|
25
|
+
}
|
|
26
|
+
export default JwtService;
|
|
27
|
+
//# sourceMappingURL=JwtService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JwtService.d.ts","sourceRoot":"","sources":["../../../src/services/auth/JwtService.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;CACxB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAS;IAE3C;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;IAYxC;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU;IAe7C;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAQpD;;OAEG;IACH,MAAM,CAAC,YAAY,IAAI,MAAM;CAK9B;AAED,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.JwtService = void 0;
|
|
7
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
+
const environment_1 = __importDefault(require("../../config/environment"));
|
|
9
|
+
class JwtService {
|
|
10
|
+
/**
|
|
11
|
+
* Generate JWT token for a user
|
|
12
|
+
*/
|
|
13
|
+
static generateToken(user) {
|
|
14
|
+
const payload = {
|
|
15
|
+
userId: user.id,
|
|
16
|
+
username: user.username,
|
|
17
|
+
role: user.role,
|
|
18
|
+
};
|
|
19
|
+
return jsonwebtoken_1.default.sign(payload, environment_1.default.JWT_SECRET, {
|
|
20
|
+
expiresIn: this.EXPIRES_IN,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Verify and decode JWT token
|
|
25
|
+
*/
|
|
26
|
+
static verifyToken(token) {
|
|
27
|
+
try {
|
|
28
|
+
return jsonwebtoken_1.default.verify(token, environment_1.default.JWT_SECRET);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error instanceof Error) {
|
|
32
|
+
if (error.name === 'TokenExpiredError') {
|
|
33
|
+
throw new Error('Token has expired');
|
|
34
|
+
}
|
|
35
|
+
else if (error.name === 'JsonWebTokenError') {
|
|
36
|
+
throw new Error('Invalid token');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Decode token without verification (for debugging)
|
|
44
|
+
*/
|
|
45
|
+
static decodeToken(token) {
|
|
46
|
+
try {
|
|
47
|
+
return jsonwebtoken_1.default.decode(token);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get token expiration time in seconds
|
|
55
|
+
*/
|
|
56
|
+
static getExpiresIn() {
|
|
57
|
+
// Convert '24h' to seconds
|
|
58
|
+
const hours = parseInt(this.EXPIRES_IN.replace('h', ''));
|
|
59
|
+
return hours * 60 * 60;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.JwtService = JwtService;
|
|
63
|
+
JwtService.EXPIRES_IN = '24h';
|
|
64
|
+
exports.default = JwtService;
|
|
65
|
+
//# sourceMappingURL=JwtService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JwtService.js","sourceRoot":"","sources":["../../../src/services/auth/JwtService.ts"],"names":[],"mappings":";;;;;;AAAA,gEAA+B;AAC/B,2EAA8C;AAS9C,MAAa,UAAU;IAGrB;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,IAAU;QAC7B,MAAM,OAAO,GAAe;YAC1B,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,CAAC;QAEF,OAAO,sBAAG,CAAC,IAAI,CAAC,OAAO,EAAE,qBAAM,CAAC,UAAU,EAAE;YAC1C,SAAS,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,KAAa;QAC9B,IAAI,CAAC;YACH,OAAO,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,qBAAM,CAAC,UAAU,CAAe,CAAC;QAC5D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;oBACvC,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBACvC,CAAC;qBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;oBAC9C,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,KAAa;QAC9B,IAAI,CAAC;YACH,OAAO,sBAAG,CAAC,MAAM,CAAC,KAAK,CAAe,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,YAAY;QACjB,2BAA2B;QAC3B,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QACzD,OAAO,KAAK,GAAG,EAAE,GAAG,EAAE,CAAC;IACzB,CAAC;;AAtDH,gCAuDC;AAtDyB,qBAAU,GAAG,KAAK,CAAC;AAwD7C,kBAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export declare class TokenRefreshService {
|
|
2
|
+
private static instance;
|
|
3
|
+
private refreshIntervals;
|
|
4
|
+
private constructor();
|
|
5
|
+
static getInstance(): TokenRefreshService;
|
|
6
|
+
/**
|
|
7
|
+
* Start monitoring a token for refresh
|
|
8
|
+
*/
|
|
9
|
+
start(tokenId: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Stop monitoring a token
|
|
12
|
+
*/
|
|
13
|
+
stop(tokenId: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Stop all token monitoring
|
|
16
|
+
*/
|
|
17
|
+
stopAll(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Check if token needs refresh and refresh if needed
|
|
20
|
+
*/
|
|
21
|
+
private checkAndRefresh;
|
|
22
|
+
/**
|
|
23
|
+
* Determine if token should be refreshed
|
|
24
|
+
*/
|
|
25
|
+
private shouldRefresh;
|
|
26
|
+
/**
|
|
27
|
+
* Refresh token using provider-specific service
|
|
28
|
+
*/
|
|
29
|
+
private refreshToken;
|
|
30
|
+
/**
|
|
31
|
+
* Update credential file with refreshed tokens
|
|
32
|
+
*/
|
|
33
|
+
private updateCredentialFile;
|
|
34
|
+
}
|
|
35
|
+
export default TokenRefreshService;
|
|
36
|
+
//# sourceMappingURL=TokenRefreshService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenRefreshService.d.ts","sourceRoot":"","sources":["../../../src/services/auth/TokenRefreshService.ts"],"names":[],"mappings":"AAWA,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAsB;IAC7C,OAAO,CAAC,gBAAgB,CAAqC;IAE7D,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,mBAAmB;IAOzC;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAsB5B;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAS3B;;OAEG;IACH,OAAO,IAAI,IAAI;IAMf;;OAEG;YACW,eAAe;IA0C7B;;OAEG;IACH,OAAO,CAAC,aAAa;IAarB;;OAEG;YACW,YAAY;IAmB1B;;OAEG;YACW,oBAAoB;CAkDnC;AAED,eAAe,mBAAmB,CAAC"}
|