@flink-app/github-app-plugin 0.12.1-alpha.38
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/CHANGELOG.md +209 -0
- package/LICENSE +21 -0
- package/README.md +667 -0
- package/SECURITY.md +498 -0
- package/dist/GitHubAppInternalContext.d.ts +44 -0
- package/dist/GitHubAppInternalContext.js +2 -0
- package/dist/GitHubAppPlugin.d.ts +45 -0
- package/dist/GitHubAppPlugin.js +367 -0
- package/dist/GitHubAppPluginContext.d.ts +242 -0
- package/dist/GitHubAppPluginContext.js +2 -0
- package/dist/GitHubAppPluginOptions.d.ts +369 -0
- package/dist/GitHubAppPluginOptions.js +2 -0
- package/dist/handlers/InitiateInstallation.d.ts +32 -0
- package/dist/handlers/InitiateInstallation.js +66 -0
- package/dist/handlers/InstallationCallback.d.ts +42 -0
- package/dist/handlers/InstallationCallback.js +248 -0
- package/dist/handlers/UninstallHandler.d.ts +37 -0
- package/dist/handlers/UninstallHandler.js +153 -0
- package/dist/handlers/WebhookHandler.d.ts +54 -0
- package/dist/handlers/WebhookHandler.js +157 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +23 -0
- package/dist/repos/GitHubAppSessionRepo.d.ts +24 -0
- package/dist/repos/GitHubAppSessionRepo.js +32 -0
- package/dist/repos/GitHubInstallationRepo.d.ts +53 -0
- package/dist/repos/GitHubInstallationRepo.js +83 -0
- package/dist/repos/GitHubWebhookEventRepo.d.ts +29 -0
- package/dist/repos/GitHubWebhookEventRepo.js +42 -0
- package/dist/schemas/GitHubAppSession.d.ts +13 -0
- package/dist/schemas/GitHubAppSession.js +2 -0
- package/dist/schemas/GitHubInstallation.d.ts +28 -0
- package/dist/schemas/GitHubInstallation.js +2 -0
- package/dist/schemas/InstallationCallbackRequest.d.ts +10 -0
- package/dist/schemas/InstallationCallbackRequest.js +2 -0
- package/dist/schemas/WebhookEvent.d.ts +16 -0
- package/dist/schemas/WebhookEvent.js +2 -0
- package/dist/schemas/WebhookPayload.d.ts +35 -0
- package/dist/schemas/WebhookPayload.js +2 -0
- package/dist/services/GitHubAPIClient.d.ts +143 -0
- package/dist/services/GitHubAPIClient.js +167 -0
- package/dist/services/GitHubAuthService.d.ts +85 -0
- package/dist/services/GitHubAuthService.js +160 -0
- package/dist/services/WebhookValidator.d.ts +93 -0
- package/dist/services/WebhookValidator.js +123 -0
- package/dist/utils/error-utils.d.ts +67 -0
- package/dist/utils/error-utils.js +121 -0
- package/dist/utils/jwt-utils.d.ts +35 -0
- package/dist/utils/jwt-utils.js +67 -0
- package/dist/utils/state-utils.d.ts +38 -0
- package/dist/utils/state-utils.js +74 -0
- package/dist/utils/token-cache-utils.d.ts +47 -0
- package/dist/utils/token-cache-utils.js +74 -0
- package/dist/utils/webhook-signature-utils.d.ts +22 -0
- package/dist/utils/webhook-signature-utils.js +57 -0
- package/examples/basic-installation.ts +246 -0
- package/examples/create-issue.ts +392 -0
- package/examples/error-handling.ts +396 -0
- package/examples/multi-event-webhook.ts +367 -0
- package/examples/organization-installation.ts +316 -0
- package/examples/repository-access.ts +480 -0
- package/examples/webhook-handling.ts +343 -0
- package/examples/with-jwt-auth.ts +319 -0
- package/package.json +41 -0
- package/spec/core-utilities.spec.ts +243 -0
- package/spec/handlers.spec.ts +216 -0
- package/spec/helpers/reporter.ts +41 -0
- package/spec/integration-and-security.spec.ts +483 -0
- package/spec/plugin-core.spec.ts +258 -0
- package/spec/project-setup.spec.ts +56 -0
- package/spec/repos-and-schemas.spec.ts +288 -0
- package/spec/services.spec.ts +108 -0
- package/spec/support/jasmine.json +7 -0
- package/src/GitHubAppPlugin.ts +411 -0
- package/src/GitHubAppPluginContext.ts +254 -0
- package/src/GitHubAppPluginOptions.ts +412 -0
- package/src/handlers/InstallationCallback.ts +292 -0
- package/src/handlers/WebhookHandler.ts +179 -0
- package/src/index.ts +29 -0
- package/src/repos/GitHubAppSessionRepo.ts +36 -0
- package/src/repos/GitHubInstallationRepo.ts +95 -0
- package/src/repos/GitHubWebhookEventRepo.ts +48 -0
- package/src/schemas/GitHubAppSession.ts +13 -0
- package/src/schemas/GitHubInstallation.ts +28 -0
- package/src/schemas/InstallationCallbackRequest.ts +10 -0
- package/src/schemas/WebhookEvent.ts +16 -0
- package/src/schemas/WebhookPayload.ts +35 -0
- package/src/services/GitHubAPIClient.ts +244 -0
- package/src/services/GitHubAuthService.ts +188 -0
- package/src/services/WebhookValidator.ts +159 -0
- package/src/utils/error-utils.ts +148 -0
- package/src/utils/jwt-utils.ts +64 -0
- package/src/utils/state-utils.ts +72 -0
- package/src/utils/token-cache-utils.ts +89 -0
- package/src/utils/webhook-signature-utils.ts +57 -0
- package/tsconfig.dist.json +4 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installation success callback parameters
|
|
3
|
+
*
|
|
4
|
+
* Provided to the onInstallationSuccess callback when a user successfully
|
|
5
|
+
* installs the GitHub App and grants access to repositories.
|
|
6
|
+
*/
|
|
7
|
+
export interface InstallationSuccessParams {
|
|
8
|
+
/** GitHub installation ID */
|
|
9
|
+
installationId: number;
|
|
10
|
+
/** GitHub account (user or organization) where app was installed */
|
|
11
|
+
account: {
|
|
12
|
+
/** Account ID on GitHub */
|
|
13
|
+
id: number;
|
|
14
|
+
/** Account username or organization name */
|
|
15
|
+
login: string;
|
|
16
|
+
/** Account type */
|
|
17
|
+
type: "User" | "Organization";
|
|
18
|
+
/** Profile picture URL */
|
|
19
|
+
avatarUrl?: string;
|
|
20
|
+
};
|
|
21
|
+
/** Repositories the user granted access to */
|
|
22
|
+
repositories: {
|
|
23
|
+
/** Repository ID on GitHub */
|
|
24
|
+
id: number;
|
|
25
|
+
/** Repository name (without owner) */
|
|
26
|
+
name: string;
|
|
27
|
+
/** Full repository name (owner/repo) */
|
|
28
|
+
fullName: string;
|
|
29
|
+
/** Whether repository is private */
|
|
30
|
+
private: boolean;
|
|
31
|
+
}[];
|
|
32
|
+
/** Permissions granted to the app (e.g., { contents: 'read', issues: 'write' }) */
|
|
33
|
+
permissions: Record<string, string>;
|
|
34
|
+
/** Webhook events the app is subscribed to */
|
|
35
|
+
events: string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Installation success callback response
|
|
39
|
+
*
|
|
40
|
+
* Return this from onInstallationSuccess to link the installation
|
|
41
|
+
* to a user in your application and redirect the user.
|
|
42
|
+
*/
|
|
43
|
+
export interface InstallationSuccessResponse {
|
|
44
|
+
/**
|
|
45
|
+
* User ID in your application to link this installation to
|
|
46
|
+
*
|
|
47
|
+
* The plugin stores this mapping to enable repository access checks.
|
|
48
|
+
* Get this from your authentication system (session, JWT, etc.)
|
|
49
|
+
*/
|
|
50
|
+
userId: string;
|
|
51
|
+
/**
|
|
52
|
+
* Optional URL to redirect user after installation
|
|
53
|
+
*
|
|
54
|
+
* If not provided, a default success page will be shown.
|
|
55
|
+
* Use this to redirect users to your dashboard or specific page.
|
|
56
|
+
*
|
|
57
|
+
* @example "/dashboard/github"
|
|
58
|
+
* @example "/repos?installation=success"
|
|
59
|
+
*/
|
|
60
|
+
redirectUrl?: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Installation error callback parameters
|
|
64
|
+
*
|
|
65
|
+
* Provided to the onInstallationError callback when installation fails.
|
|
66
|
+
*/
|
|
67
|
+
export interface InstallationErrorParams {
|
|
68
|
+
/** Error information */
|
|
69
|
+
error: {
|
|
70
|
+
/** Error code in kebab-case (e.g., 'invalid-state', 'session-expired') */
|
|
71
|
+
code: string;
|
|
72
|
+
/** User-friendly error message */
|
|
73
|
+
message: string;
|
|
74
|
+
/** Additional error details for debugging */
|
|
75
|
+
details?: any;
|
|
76
|
+
};
|
|
77
|
+
/** Installation ID if available (may be undefined if error occurred before installation) */
|
|
78
|
+
installationId?: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Installation error callback response
|
|
82
|
+
*
|
|
83
|
+
* Return this from onInstallationError to redirect the user
|
|
84
|
+
* to an error page or retry flow.
|
|
85
|
+
*/
|
|
86
|
+
export interface InstallationErrorResponse {
|
|
87
|
+
/**
|
|
88
|
+
* Optional URL to redirect user after error
|
|
89
|
+
*
|
|
90
|
+
* Use this to show error messages or allow retry.
|
|
91
|
+
*
|
|
92
|
+
* @example "/error?message=installation-failed"
|
|
93
|
+
* @example "/github/install?retry=true"
|
|
94
|
+
*/
|
|
95
|
+
redirectUrl?: string;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Webhook event callback parameters
|
|
99
|
+
*
|
|
100
|
+
* Provided to the onWebhookEvent callback when a webhook event is received
|
|
101
|
+
* from GitHub. The plugin validates the webhook signature before calling this.
|
|
102
|
+
*/
|
|
103
|
+
export interface WebhookEventParams {
|
|
104
|
+
/**
|
|
105
|
+
* GitHub event type
|
|
106
|
+
*
|
|
107
|
+
* Common events: 'push', 'pull_request', 'issues', 'installation',
|
|
108
|
+
* 'pull_request_review', 'issue_comment', 'release', etc.
|
|
109
|
+
*/
|
|
110
|
+
event: string;
|
|
111
|
+
/**
|
|
112
|
+
* Event action (if applicable)
|
|
113
|
+
*
|
|
114
|
+
* Examples: 'opened', 'closed', 'reopened', 'created', 'deleted', etc.
|
|
115
|
+
* Not all events have actions.
|
|
116
|
+
*/
|
|
117
|
+
action?: string;
|
|
118
|
+
/**
|
|
119
|
+
* Full webhook payload from GitHub
|
|
120
|
+
*
|
|
121
|
+
* Structure varies by event type. See GitHub webhook documentation
|
|
122
|
+
* for payload schemas.
|
|
123
|
+
*/
|
|
124
|
+
payload: Record<string, any>;
|
|
125
|
+
/** Installation ID that triggered the webhook */
|
|
126
|
+
installationId: number;
|
|
127
|
+
/**
|
|
128
|
+
* Unique delivery ID from GitHub (X-GitHub-Delivery header)
|
|
129
|
+
*
|
|
130
|
+
* Use this for debugging and tracking webhook deliveries.
|
|
131
|
+
*/
|
|
132
|
+
deliveryId: string;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Configuration options for GitHub App Plugin
|
|
136
|
+
*
|
|
137
|
+
* Configure the plugin with your GitHub App credentials, callbacks,
|
|
138
|
+
* and optional settings for database, caching, and features.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* githubAppPlugin({
|
|
143
|
+
* // Required: GitHub App credentials
|
|
144
|
+
* appId: process.env.GITHUB_APP_ID!,
|
|
145
|
+
* privateKey: process.env.GITHUB_APP_PRIVATE_KEY_BASE64!, // Base64 encoded
|
|
146
|
+
* webhookSecret: process.env.GITHUB_WEBHOOK_SECRET!,
|
|
147
|
+
* clientId: process.env.GITHUB_APP_CLIENT_ID!,
|
|
148
|
+
* clientSecret: process.env.GITHUB_APP_CLIENT_SECRET!,
|
|
149
|
+
*
|
|
150
|
+
* // Required: Installation success callback
|
|
151
|
+
* onInstallationSuccess: async ({ installationId, repositories }, ctx) => {
|
|
152
|
+
* const userId = getUserId(ctx); // Your auth system
|
|
153
|
+
* return { userId, redirectUrl: '/dashboard' };
|
|
154
|
+
* },
|
|
155
|
+
*
|
|
156
|
+
* // Optional: Handle webhook events
|
|
157
|
+
* onWebhookEvent: async ({ event, payload }, ctx) => {
|
|
158
|
+
* if (event === 'push') {
|
|
159
|
+
* console.log('Push event received');
|
|
160
|
+
* }
|
|
161
|
+
* }
|
|
162
|
+
* })
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export interface GitHubAppPluginOptions {
|
|
166
|
+
/**
|
|
167
|
+
* GitHub App ID
|
|
168
|
+
*
|
|
169
|
+
* Found in your GitHub App settings page.
|
|
170
|
+
*
|
|
171
|
+
* @example "123456"
|
|
172
|
+
*/
|
|
173
|
+
appId: string;
|
|
174
|
+
/**
|
|
175
|
+
* GitHub App private key (Base64 encoded PEM format)
|
|
176
|
+
*
|
|
177
|
+
* Download the private key from GitHub App settings, then base64 encode it.
|
|
178
|
+
* This format plays nicely with environment variables (no line break issues).
|
|
179
|
+
* Supports both PKCS#1 and PKCS#8 formats (auto-detected after decoding).
|
|
180
|
+
*
|
|
181
|
+
* To encode your private key:
|
|
182
|
+
* ```bash
|
|
183
|
+
* # On macOS/Linux:
|
|
184
|
+
* base64 -i private-key.pem | tr -d '\n'
|
|
185
|
+
*
|
|
186
|
+
* # On Windows (PowerShell):
|
|
187
|
+
* [Convert]::ToBase64String([IO.File]::ReadAllBytes("private-key.pem"))
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* @example "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0..."
|
|
191
|
+
*/
|
|
192
|
+
privateKey: string;
|
|
193
|
+
/**
|
|
194
|
+
* Webhook secret for signature validation
|
|
195
|
+
*
|
|
196
|
+
* Set in GitHub App settings. Used to validate webhook signatures
|
|
197
|
+
* using HMAC-SHA256. Generate a strong random string.
|
|
198
|
+
*
|
|
199
|
+
* @example "your-webhook-secret-here"
|
|
200
|
+
*/
|
|
201
|
+
webhookSecret: string;
|
|
202
|
+
/**
|
|
203
|
+
* GitHub App client ID
|
|
204
|
+
*
|
|
205
|
+
* Found in your GitHub App settings page.
|
|
206
|
+
*
|
|
207
|
+
* @example "Iv1.abc123def456"
|
|
208
|
+
*/
|
|
209
|
+
clientId: string;
|
|
210
|
+
/**
|
|
211
|
+
* GitHub App client secret
|
|
212
|
+
*
|
|
213
|
+
* Generate in GitHub App settings. Store in environment variables.
|
|
214
|
+
*
|
|
215
|
+
* @example "your-client-secret-here"
|
|
216
|
+
*/
|
|
217
|
+
clientSecret: string;
|
|
218
|
+
/**
|
|
219
|
+
* GitHub App slug (optional)
|
|
220
|
+
*
|
|
221
|
+
* Used in installation URL. Auto-detected if not provided.
|
|
222
|
+
* Found in your GitHub App settings page.
|
|
223
|
+
*
|
|
224
|
+
* @default Auto-detected from GitHub API
|
|
225
|
+
* @example "my-flink-app"
|
|
226
|
+
*/
|
|
227
|
+
appSlug?: string;
|
|
228
|
+
/**
|
|
229
|
+
* GitHub API base URL (optional)
|
|
230
|
+
*
|
|
231
|
+
* Use for GitHub Enterprise Server installations.
|
|
232
|
+
* For github.com, use the default.
|
|
233
|
+
*
|
|
234
|
+
* @default "https://api.github.com"
|
|
235
|
+
* @example "https://github.mycompany.com/api/v3"
|
|
236
|
+
*/
|
|
237
|
+
baseUrl?: string;
|
|
238
|
+
/**
|
|
239
|
+
* Callback invoked after successful installation
|
|
240
|
+
*
|
|
241
|
+
* REQUIRED. Called when user completes GitHub App installation.
|
|
242
|
+
* Return userId to link installation and optional redirectUrl.
|
|
243
|
+
*
|
|
244
|
+
* @param params - Installation data from GitHub
|
|
245
|
+
* @param ctx - Flink context with repos and plugins
|
|
246
|
+
* @returns Object with userId and optional redirectUrl
|
|
247
|
+
*
|
|
248
|
+
* @throws Should not throw - errors are caught and passed to onInstallationError
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```typescript
|
|
252
|
+
* async ({ installationId, repositories, account }, ctx) => {
|
|
253
|
+
* const userId = ctx.auth?.tokenData?.userId || 'anonymous';
|
|
254
|
+
* return {
|
|
255
|
+
* userId,
|
|
256
|
+
* redirectUrl: '/dashboard/github'
|
|
257
|
+
* };
|
|
258
|
+
* }
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
onInstallationSuccess: (params: InstallationSuccessParams, ctx: any) => Promise<InstallationSuccessResponse>;
|
|
262
|
+
/**
|
|
263
|
+
* Callback invoked when installation fails (optional)
|
|
264
|
+
*
|
|
265
|
+
* Called when installation encounters an error (invalid state,
|
|
266
|
+
* expired session, GitHub API failure, etc.)
|
|
267
|
+
*
|
|
268
|
+
* @param params - Error information
|
|
269
|
+
* @returns Object with optional redirectUrl
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* ```typescript
|
|
273
|
+
* async ({ error, installationId }) => {
|
|
274
|
+
* console.error('Installation error:', error);
|
|
275
|
+
* return {
|
|
276
|
+
* redirectUrl: `/error?code=${error.code}`
|
|
277
|
+
* };
|
|
278
|
+
* }
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
onInstallationError?: (params: InstallationErrorParams) => Promise<InstallationErrorResponse>;
|
|
282
|
+
/**
|
|
283
|
+
* Callback invoked when webhook event is received (optional)
|
|
284
|
+
*
|
|
285
|
+
* Called for each webhook event after signature validation.
|
|
286
|
+
* Process events asynchronously. Don't throw errors to prevent
|
|
287
|
+
* GitHub from retrying.
|
|
288
|
+
*
|
|
289
|
+
* @param params - Webhook event data
|
|
290
|
+
* @param ctx - Flink context with repos and plugins
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```typescript
|
|
294
|
+
* async ({ event, action, payload, installationId }, ctx) => {
|
|
295
|
+
* if (event === 'push') {
|
|
296
|
+
* console.log('Push to', payload.repository.full_name);
|
|
297
|
+
* }
|
|
298
|
+
* if (event === 'pull_request' && action === 'opened') {
|
|
299
|
+
* const client = await ctx.plugins.githubApp.getClient(installationId);
|
|
300
|
+
* await client.createIssue(...);
|
|
301
|
+
* }
|
|
302
|
+
* }
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
onWebhookEvent?: (params: WebhookEventParams, ctx: any) => Promise<void>;
|
|
306
|
+
/**
|
|
307
|
+
* MongoDB collection name for sessions (optional)
|
|
308
|
+
*
|
|
309
|
+
* Used for CSRF protection during installation flow.
|
|
310
|
+
*
|
|
311
|
+
* @default "github_app_sessions"
|
|
312
|
+
*/
|
|
313
|
+
sessionsCollectionName?: string;
|
|
314
|
+
/**
|
|
315
|
+
* MongoDB collection name for installations (optional)
|
|
316
|
+
*
|
|
317
|
+
* Stores installation-to-user mappings and repository access info.
|
|
318
|
+
*
|
|
319
|
+
* @default "github_installations"
|
|
320
|
+
*/
|
|
321
|
+
installationsCollectionName?: string;
|
|
322
|
+
/**
|
|
323
|
+
* MongoDB collection name for webhook events (optional)
|
|
324
|
+
*
|
|
325
|
+
* Only used if logWebhookEvents is enabled.
|
|
326
|
+
*
|
|
327
|
+
* @default "github_webhook_events"
|
|
328
|
+
*/
|
|
329
|
+
webhookEventsCollectionName?: string;
|
|
330
|
+
/**
|
|
331
|
+
* Installation token cache TTL in seconds (optional)
|
|
332
|
+
*
|
|
333
|
+
* How long to cache installation access tokens in memory.
|
|
334
|
+
* Tokens expire after 60 minutes. Set to 55 minutes (3300 seconds)
|
|
335
|
+
* for 5-minute safety margin.
|
|
336
|
+
*
|
|
337
|
+
* @default 3300 (55 minutes)
|
|
338
|
+
* @example 3000 (50 minutes)
|
|
339
|
+
*/
|
|
340
|
+
tokenCacheTTL?: number;
|
|
341
|
+
/**
|
|
342
|
+
* Session TTL in seconds (optional)
|
|
343
|
+
*
|
|
344
|
+
* How long CSRF protection sessions are valid.
|
|
345
|
+
* Sessions are automatically deleted via MongoDB TTL index.
|
|
346
|
+
*
|
|
347
|
+
* @default 600 (10 minutes)
|
|
348
|
+
* @example 300 (5 minutes)
|
|
349
|
+
*/
|
|
350
|
+
sessionTTL?: number;
|
|
351
|
+
/**
|
|
352
|
+
* Register HTTP handlers automatically (optional)
|
|
353
|
+
*
|
|
354
|
+
* If true, registers installation and webhook handlers.
|
|
355
|
+
* Set to false if you want to implement custom handlers.
|
|
356
|
+
*
|
|
357
|
+
* @default true
|
|
358
|
+
*/
|
|
359
|
+
registerRoutes?: boolean;
|
|
360
|
+
/**
|
|
361
|
+
* Log webhook events to MongoDB (optional)
|
|
362
|
+
*
|
|
363
|
+
* If true, stores all webhook events in database for debugging.
|
|
364
|
+
* Useful for development but may consume storage in production.
|
|
365
|
+
*
|
|
366
|
+
* @default false
|
|
367
|
+
*/
|
|
368
|
+
logWebhookEvents?: boolean;
|
|
369
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub App Installation Initiation Handler
|
|
3
|
+
*
|
|
4
|
+
* Initiates the GitHub App installation flow by:
|
|
5
|
+
* 1. Generating a cryptographically secure state parameter for CSRF protection
|
|
6
|
+
* 2. Creating an installation session to track the flow
|
|
7
|
+
* 3. Building GitHub's installation URL with state parameter
|
|
8
|
+
* 4. Redirecting the user to GitHub for app installation
|
|
9
|
+
*
|
|
10
|
+
* Route: GET /github-app/install?user_id={optional_user_id}
|
|
11
|
+
*/
|
|
12
|
+
import { GetHandler, RouteProps } from "@flink-app/flink";
|
|
13
|
+
/**
|
|
14
|
+
* Query parameters for the handler
|
|
15
|
+
*/
|
|
16
|
+
interface QueryParams {
|
|
17
|
+
user_id?: string;
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Route configuration
|
|
22
|
+
* Registered programmatically by the plugin if registerRoutes is enabled
|
|
23
|
+
*/
|
|
24
|
+
export declare const Route: RouteProps;
|
|
25
|
+
/**
|
|
26
|
+
* GitHub App Installation Initiation Handler
|
|
27
|
+
*
|
|
28
|
+
* Starts the installation flow by generating CSRF state, creating a session,
|
|
29
|
+
* and redirecting to GitHub's app installation page.
|
|
30
|
+
*/
|
|
31
|
+
declare const InitiateInstallation: GetHandler<any, any, any, QueryParams>;
|
|
32
|
+
export default InitiateInstallation;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* GitHub App Installation Initiation Handler
|
|
4
|
+
*
|
|
5
|
+
* Initiates the GitHub App installation flow by:
|
|
6
|
+
* 1. Generating a cryptographically secure state parameter for CSRF protection
|
|
7
|
+
* 2. Creating an installation session to track the flow
|
|
8
|
+
* 3. Building GitHub's installation URL with state parameter
|
|
9
|
+
* 4. Redirecting the user to GitHub for app installation
|
|
10
|
+
*
|
|
11
|
+
* Route: GET /github-app/install?user_id={optional_user_id}
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.Route = void 0;
|
|
15
|
+
const flink_1 = require("@flink-app/flink");
|
|
16
|
+
const state_utils_1 = require("../utils/state-utils");
|
|
17
|
+
/**
|
|
18
|
+
* Route configuration
|
|
19
|
+
* Registered programmatically by the plugin if registerRoutes is enabled
|
|
20
|
+
*/
|
|
21
|
+
exports.Route = {
|
|
22
|
+
path: "/github-app/install",
|
|
23
|
+
method: flink_1.HttpMethod.get,
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* GitHub App Installation Initiation Handler
|
|
27
|
+
*
|
|
28
|
+
* Starts the installation flow by generating CSRF state, creating a session,
|
|
29
|
+
* and redirecting to GitHub's app installation page.
|
|
30
|
+
*/
|
|
31
|
+
const InitiateInstallation = async ({ ctx, req }) => {
|
|
32
|
+
const { user_id } = req.query;
|
|
33
|
+
try {
|
|
34
|
+
// Get plugin options
|
|
35
|
+
const { options } = ctx.plugins.githubApp;
|
|
36
|
+
// Validate that appSlug is configured
|
|
37
|
+
if (!options.appSlug) {
|
|
38
|
+
return (0, flink_1.badRequest)("GitHub App slug is not configured. Please set appSlug in plugin options.");
|
|
39
|
+
}
|
|
40
|
+
// Generate cryptographically secure state and session ID
|
|
41
|
+
const state = (0, state_utils_1.generateState)();
|
|
42
|
+
const sessionId = (0, state_utils_1.generateSessionId)();
|
|
43
|
+
// Store session for state validation in callback
|
|
44
|
+
await ctx.repos.githubAppSessionRepo.create({
|
|
45
|
+
sessionId,
|
|
46
|
+
state,
|
|
47
|
+
userId: user_id,
|
|
48
|
+
createdAt: new Date(),
|
|
49
|
+
});
|
|
50
|
+
// Build GitHub installation URL
|
|
51
|
+
const installationUrl = `https://github.com/apps/${options.appSlug}/installations/new?state=${state}`;
|
|
52
|
+
// Redirect user to GitHub's app installation page
|
|
53
|
+
return {
|
|
54
|
+
status: 302,
|
|
55
|
+
headers: {
|
|
56
|
+
Location: installationUrl,
|
|
57
|
+
},
|
|
58
|
+
data: {},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
// Handle unexpected errors
|
|
63
|
+
return (0, flink_1.internalServerError)(error.message || "Failed to initiate GitHub App installation");
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
exports.default = InitiateInstallation;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub App Installation Callback Handler
|
|
3
|
+
*
|
|
4
|
+
* Handles the callback from GitHub after app installation by:
|
|
5
|
+
* 1. Validating the state parameter to prevent CSRF attacks
|
|
6
|
+
* 2. Fetching installation details from GitHub API
|
|
7
|
+
* 3. Calling the onInstallationSuccess callback to link installation to user
|
|
8
|
+
* 4. Storing the installation in the database
|
|
9
|
+
* 5. Redirecting to the application
|
|
10
|
+
*
|
|
11
|
+
* Route: GET /github-app/callback?installation_id=...&setup_action=...&state=...
|
|
12
|
+
*/
|
|
13
|
+
import { RouteProps } from "@flink-app/flink";
|
|
14
|
+
/**
|
|
15
|
+
* Context with GitHub App Plugin
|
|
16
|
+
*
|
|
17
|
+
* Note: Using 'any' for simplicity. In a real-world scenario, you'd want to properly
|
|
18
|
+
* type the context with both FlinkContext and GitHubAppPluginContext including the repos.
|
|
19
|
+
*/
|
|
20
|
+
type InstallationCallbackContext = any;
|
|
21
|
+
/**
|
|
22
|
+
* Route configuration
|
|
23
|
+
* Registered programmatically by the plugin if registerRoutes is enabled
|
|
24
|
+
*/
|
|
25
|
+
export declare const Route: RouteProps;
|
|
26
|
+
/**
|
|
27
|
+
* GitHub App Installation Callback Handler
|
|
28
|
+
*
|
|
29
|
+
* Completes the installation flow by validating state, fetching installation
|
|
30
|
+
* details, calling the app's callback, and storing the installation.
|
|
31
|
+
*/
|
|
32
|
+
declare const InstallationCallback: ({ ctx, req }: {
|
|
33
|
+
ctx: InstallationCallbackContext;
|
|
34
|
+
req: any;
|
|
35
|
+
}) => Promise<import("@flink-app/flink").FlinkResponse<undefined> | {
|
|
36
|
+
status: number;
|
|
37
|
+
headers: {
|
|
38
|
+
Location: any;
|
|
39
|
+
};
|
|
40
|
+
data: {};
|
|
41
|
+
}>;
|
|
42
|
+
export default InstallationCallback;
|