@manojkmfsi/monodog 1.1.28 → 1.1.31
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/.env.example +1 -15
- package/CHANGELOG.md +76 -0
- package/check-db.js +58 -0
- package/create-test-session.js +50 -0
- package/dev-server.pid +1 -0
- package/dist/controllers/auth-controller.js +196 -0
- package/dist/controllers/permission-controller.js +152 -0
- package/dist/controllers/pipeline-controller.js +329 -0
- package/dist/controllers/publish-controller.js +119 -7
- package/dist/middleware/auth-middleware.js +1 -0
- package/dist/middleware/server-startup.js +19 -0
- package/dist/routes/auth-routes.js +7 -336
- package/dist/routes/permission-routes.js +4 -139
- package/dist/routes/pipeline-routes.js +76 -0
- package/dist/services/auth-service.js +239 -0
- package/dist/services/changeset-service.js +2 -13
- package/dist/services/github-actions-service.js +552 -0
- package/dist/services/permission-service.js +30 -0
- package/dist/services/pipeline-service.js +356 -0
- package/dist/types/github-actions.js +6 -0
- package/monodog-dashboard/dist/assets/index-6NrFUGfK.js +15 -0
- package/monodog-dashboard/dist/assets/index-6NrFUGfK.js.map +1 -0
- package/monodog-dashboard/dist/assets/index-DcvKt8qx.css +1 -0
- package/monodog-dashboard/dist/index.html +2 -2
- package/package.json +2 -2
- package/prisma/migrations/{20260118042615_init_database → 20260224091033_init_db}/migration.sql +58 -0
- package/prisma/schema/pipeline-audit-log.prisma +22 -0
- package/prisma/schema/release-pipeline.prisma +25 -0
- package/monodog-dashboard/dist/assets/index-7G3SCgcz.css +0 -1
- package/monodog-dashboard/dist/assets/index-BMoE990p.js +0 -13
- package/monodog-dashboard/dist/assets/index-BMoE990p.js.map +0 -1
package/.env.example
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
# GitHub OAuth Configuration
|
|
2
2
|
GITHUB_CLIENT_ID=your_client_id_here
|
|
3
3
|
GITHUB_CLIENT_SECRET=your_client_secret_here
|
|
4
|
-
OAUTH_REDIRECT_URI=http://localhost:
|
|
4
|
+
OAUTH_REDIRECT_URI=http://localhost:3010/auth/callback
|
|
5
5
|
|
|
6
|
-
# Database Configuration
|
|
7
|
-
# DATABASE_URL=postgresql://user:password@localhost:5432/monodog
|
|
8
|
-
|
|
9
|
-
# # Server Configuration
|
|
10
|
-
# SERVER_HOST=localhost
|
|
11
|
-
# SERVER_PORT=5000
|
|
12
|
-
# DASHBOARD_HOST=localhost
|
|
13
|
-
# DASHBOARD_PORT=3000
|
|
14
|
-
|
|
15
|
-
# # Logging Level (debug, info, warn, error)
|
|
16
|
-
# LOG_LEVEL=info
|
|
17
|
-
|
|
18
|
-
# # Environment
|
|
19
|
-
# NODE_ENV=development
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,81 @@
|
|
|
1
1
|
# @manojkmfsi/monoapp
|
|
2
2
|
|
|
3
|
+
## 1.1.31
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`0541cc8`](https://github.com/manojkmfsi/monodog/commit/0541cc88c639265386c29a59b09e6b63cdee6064) - vnbbnbn,n,mnm,m
|
|
8
|
+
|
|
9
|
+
- [`785a90a`](https://github.com/manojkmfsi/monodog/commit/785a90a9c15354559f13a88bf1f9486c9794fc18) - ffhjhkklnbncxdflk,
|
|
10
|
+
|
|
11
|
+
- [`3a32768`](https://github.com/manojkmfsi/monodog/commit/3a32768c4e1be683847d9308632c1d4eb85e43fd) - ccfckjjlkklkm,m.,m.,
|
|
12
|
+
|
|
13
|
+
- [`efee08b`](https://github.com/manojkmfsi/monodog/commit/efee08b5d8cc52f35b7a21dae69ca7dde5b99427) - fgkjlkn,m cgfcbv
|
|
14
|
+
|
|
15
|
+
## 1.1.30
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [`f27db43`](https://github.com/manojkmfsi/monodog/commit/f27db43277895381dbf239ffd57ebb17e7fd6e13) - sasasasasasasas
|
|
20
|
+
|
|
21
|
+
## 1.1.29
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- [`8600e0c`](https://github.com/manojkmfsi/monodog/commit/8600e0c636f76c8b9dcc8fbf7a2617d355f2d0e5) - fsfyfhfhfjjh,m
|
|
26
|
+
|
|
27
|
+
- [`188bcf2`](https://github.com/manojkmfsi/monodog/commit/188bcf2ab06b5fe58b2cea5915a7751cba3a68d2) - cxzcxvxcbvcbnb,m
|
|
28
|
+
|
|
29
|
+
- [`cfb03da`](https://github.com/manojkmfsi/monodog/commit/cfb03da50efd0b829bf4a8b4c5c2ae68c4d1a4ce) - mkjmnmnmnmnnmnm
|
|
30
|
+
|
|
31
|
+
- [`d95b183`](https://github.com/manojkmfsi/monodog/commit/d95b183ea3aa3a60f153d40d1db4049565ecaffa) - m nm nm nm nm mn nm mmm nm mn mm
|
|
32
|
+
|
|
33
|
+
- [`8abe3fb`](https://github.com/manojkmfsi/monodog/commit/8abe3fb09b2608696e6960ac0fdb8e0a9112dfa7) - xzdfdguiulmn cxdtyj
|
|
34
|
+
|
|
35
|
+
- [`9add854`](https://github.com/manojkmfsi/monodog/commit/9add854171041d38161916c2ce5ed34af471614a) - hbmjnbmm,n,,m,
|
|
36
|
+
|
|
37
|
+
- [`5f9b61e`](https://github.com/manojkmfsi/monodog/commit/5f9b61e73c8d1c460dac445aa9c5ae52ed053883) - cxgfhgjmnmnm,k,m
|
|
38
|
+
|
|
39
|
+
- [`bde7bfb`](https://github.com/manojkmfsi/monodog/commit/bde7bfb74376917ab590c8f0d831c3aa0a9e0482) - vnmn,nkjlkn,mnm,
|
|
40
|
+
|
|
41
|
+
- [`e67b026`](https://github.com/manojkmfsi/monodog/commit/e67b02689d82fb4cae0ca917fdb829c3d23d3b9d) - drkjk,,kjudscxvxvvvvnm
|
|
42
|
+
|
|
43
|
+
- [`6b78e09`](https://github.com/manojkmfsi/monodog/commit/6b78e09e6e090ece45485b0e43b1b6e5a537e4eb) - fcdgcbvnkmkllml.m.
|
|
44
|
+
|
|
45
|
+
- [`1a74552`](https://github.com/manojkmfsi/monodog/commit/1a74552277f8deaef831649ad424ea41c77fd467) - nhuyfgxbvnbmklm, .,nmkn,
|
|
46
|
+
|
|
47
|
+
- [`fe566fd`](https://github.com/manojkmfsi/monodog/commit/fe566fdb7041ce079e8afe78ebdb4b477f0cae44) - fghjvvnvnbn
|
|
48
|
+
|
|
49
|
+
- [`79566ae`](https://github.com/manojkmfsi/monodog/commit/79566ae23e3f30a03482134f35b5491e289d2775) - adssdxvcvbcbvcxvcbvcb
|
|
50
|
+
|
|
51
|
+
- [`804ddf2`](https://github.com/manojkmfsi/monodog/commit/804ddf22cf845aa2c980bff9488a04e251be119a) - fxcbcvcxcbvnbvnb
|
|
52
|
+
|
|
53
|
+
- [`07e1878`](https://github.com/manojkmfsi/monodog/commit/07e18786e6f3d8dad57f90822af93bd578c9c3ae) - bvcghmjnm,nmnmhkjhn,mn
|
|
54
|
+
|
|
55
|
+
- [`faa4e0c`](https://github.com/manojkmfsi/monodog/commit/faa4e0cb48e0b1f8eae6aa93f104924452076b94) - mnmmmmnmnmn,mn,mnmn,
|
|
56
|
+
|
|
57
|
+
- [`4ed3483`](https://github.com/manojkmfsi/monodog/commit/4ed34834edea9c6789ffbf93c1354f9752b59b8b) - n,mnmnmnmn,mnm,,m
|
|
58
|
+
|
|
59
|
+
- [`dd47e0b`](https://github.com/manojkmfsi/monodog/commit/dd47e0b8480f14a78b958f3ff68d3b41082f3465) - mnn,mn,mn,n,mn,,
|
|
60
|
+
|
|
61
|
+
- [`621bee1`](https://github.com/manojkmfsi/monodog/commit/621bee11b6194ee56fd90c130a4b3c83b386831a) - kmmnmmn,n,m,m, n,m
|
|
62
|
+
|
|
63
|
+
- [`ec7e1b0`](https://github.com/manojkmfsi/monodog/commit/ec7e1b0817ae540ece67576fbceb7486dcadc48f) - mnm,n,n,mn,mn,m,m,m,
|
|
64
|
+
|
|
65
|
+
- [`411523b`](https://github.com/manojkmfsi/monodog/commit/411523b813a96fcfd46c3e459bcd887c255fd2e7) - mnmn,mn,mn,m.,m.,m.,m,m.,
|
|
66
|
+
|
|
67
|
+
- [`ec19a7c`](https://github.com/manojkmfsi/monodog/commit/ec19a7ccff425f7319c24d0506a147fcfdd0e9ca) - vbcbvbnvnmbnmbnmnm
|
|
68
|
+
|
|
69
|
+
- [`6818670`](https://github.com/manojkmfsi/monodog/commit/6818670424be6bdb98e1fd2e04f1fe985638e67e) - cxxvcvcbvbnvnbvnmnm
|
|
70
|
+
|
|
71
|
+
- [`10eac2e`](https://github.com/manojkmfsi/monodog/commit/10eac2ee72753474d4ec0d9ba2ba3ebdd4639c96) - sdhgjhkjhkjjkkkjn
|
|
72
|
+
|
|
73
|
+
- [`4c924c9`](https://github.com/manojkmfsi/monodog/commit/4c924c918f93cbd54c1c752060a6bdaab45e987d) - wdassdsfddfsdffdgfdsgfsgfg
|
|
74
|
+
|
|
75
|
+
- [`a9e5e26`](https://github.com/manojkmfsi/monodog/commit/a9e5e2680f49c448c49e3a1c414d5c2533a5e9cf) - nnknknnnknkn,,mnm,
|
|
76
|
+
|
|
77
|
+
- [`d559595`](https://github.com/manojkmfsi/monodog/commit/d559595e3b56371a102a21244d0d6c5696541bd3) - dsdsmnd,mns,mnd,msnd,msn,md
|
|
78
|
+
|
|
3
79
|
## 1.1.28
|
|
4
80
|
|
|
5
81
|
### Patch Changes
|
package/check-db.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const { PrismaClient } = require('@prisma/client');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
// Load config similar to the app
|
|
6
|
+
let databasePath = 'file:./monodog.db'; // default
|
|
7
|
+
|
|
8
|
+
// Try to read monodog-config.json
|
|
9
|
+
try {
|
|
10
|
+
const configPath = path.join(__dirname, 'monodog-config.json');
|
|
11
|
+
if (fs.existsSync(configPath)) {
|
|
12
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
13
|
+
databasePath = config.database?.path || databasePath;
|
|
14
|
+
}
|
|
15
|
+
} catch (e) {
|
|
16
|
+
console.warn('Could not read config:', e.message);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
console.log(`Database URL: ${databasePath}\n`);
|
|
20
|
+
|
|
21
|
+
async function checkDatabase() {
|
|
22
|
+
const prisma = new PrismaClient({
|
|
23
|
+
datasources: {
|
|
24
|
+
db: {
|
|
25
|
+
url: databasePath,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
console.log('=== Database Status ===\n');
|
|
32
|
+
|
|
33
|
+
// Check ReleasePipeline count
|
|
34
|
+
const pipelineCount = await prisma.releasePipeline.count();
|
|
35
|
+
console.log(`Total pipelines in database: ${pipelineCount}\n`);
|
|
36
|
+
|
|
37
|
+
if (pipelineCount > 0) {
|
|
38
|
+
const pipelines = await prisma.releasePipeline.findMany({
|
|
39
|
+
take: 5,
|
|
40
|
+
orderBy: { createdAt: 'desc' },
|
|
41
|
+
});
|
|
42
|
+
console.log('Latest pipelines:');
|
|
43
|
+
pipelines.forEach(p => {
|
|
44
|
+
console.log(` - ${p.packageName} v${p.releaseVersion} (${p.currentStatus})`);
|
|
45
|
+
console.log(` Triggered by: ${p.triggeredBy} at ${p.triggeredAt}`);
|
|
46
|
+
console.log(` Owner/Repo: ${p.owner}/${p.repo}`);
|
|
47
|
+
console.log('');
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
process.exit(0);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error('Error:', error.message);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
checkDatabase();
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This script creates a test session by directly calling the auth middleware's storeSession function
|
|
5
|
+
* It simulates what happens after a successful GitHub OAuth login
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { storeSession } = require('./dist/middleware/auth-middleware');
|
|
9
|
+
|
|
10
|
+
// Create a mock session
|
|
11
|
+
const mockSession = {
|
|
12
|
+
accessToken: 'gho_test_token_' + Math.random().toString(36).substr(2, 9),
|
|
13
|
+
expiresIn: 3600,
|
|
14
|
+
expiresAt: Date.now() + 24 * 60 * 60 * 1000,
|
|
15
|
+
user: {
|
|
16
|
+
id: 12345,
|
|
17
|
+
login: 'testuser',
|
|
18
|
+
name: 'Test User',
|
|
19
|
+
email: 'test@example.com',
|
|
20
|
+
avatar_url: 'https://avatars.githubusercontent.com/u/12345?v=4',
|
|
21
|
+
public_repos: 5,
|
|
22
|
+
followers: 10,
|
|
23
|
+
following: 5,
|
|
24
|
+
},
|
|
25
|
+
scopes: ['repo', 'read:user'],
|
|
26
|
+
permission: {
|
|
27
|
+
permission: 'maintain',
|
|
28
|
+
role: 'Maintainer',
|
|
29
|
+
userId: 12345,
|
|
30
|
+
username: 'testuser',
|
|
31
|
+
owner: 'manojkmfsi',
|
|
32
|
+
repo: 'MonoDog',
|
|
33
|
+
cachedAt: Date.now(),
|
|
34
|
+
ttl: 3600000,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const token = storeSession(mockSession);
|
|
40
|
+
console.log('✅ Test session created successfully!');
|
|
41
|
+
console.log(`\nSession Token: ${token}`);
|
|
42
|
+
console.log(`User: ${mockSession.user.login}`);
|
|
43
|
+
console.log(`Permission: ${mockSession.permission.permission}`);
|
|
44
|
+
console.log(`Expires at: ${new Date(mockSession.expiresAt).toISOString()}`);
|
|
45
|
+
console.log(`\nYou can use this token in API requests:`);
|
|
46
|
+
console.log(`curl -H "Authorization: Bearer ${token}" http://localhost:8999/api/publish/trigger`);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error('❌ Failed to create session:', error.message);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
package/dev-server.pid
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
22401
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Authentication Controller
|
|
4
|
+
* Thin controller that handles HTTP concerns and delegates business logic to auth-service
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.refresh = exports.logout = exports.validate = exports.me = exports.callback = exports.login = void 0;
|
|
8
|
+
const auth_service_1 = require("../services/auth-service");
|
|
9
|
+
const logger_1 = require("../middleware/logger");
|
|
10
|
+
/**
|
|
11
|
+
* Start OAuth login flow
|
|
12
|
+
* GET /auth/login
|
|
13
|
+
*/
|
|
14
|
+
const login = (req, res) => {
|
|
15
|
+
try {
|
|
16
|
+
const redirectUrl = req.query.redirect || '/';
|
|
17
|
+
const result = (0, auth_service_1.initiateLogin)(redirectUrl);
|
|
18
|
+
res.json({
|
|
19
|
+
success: true,
|
|
20
|
+
authUrl: result.authUrl,
|
|
21
|
+
message: 'Redirect to this URL to authenticate with GitHub',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
logger_1.AppLogger.error(`Login initiation failed: ${error}`);
|
|
26
|
+
res.status(500).json({
|
|
27
|
+
success: false,
|
|
28
|
+
error: 'Login failed',
|
|
29
|
+
message: error instanceof Error ? error.message : 'Failed to initiate GitHub OAuth flow',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
exports.login = login;
|
|
34
|
+
/**
|
|
35
|
+
* OAuth callback handler
|
|
36
|
+
* GET /auth/callback?code=...&state=...
|
|
37
|
+
*/
|
|
38
|
+
const callback = async (req, res) => {
|
|
39
|
+
try {
|
|
40
|
+
const { code, state, error, error_description } = req.query;
|
|
41
|
+
// Handle OAuth errors from GitHub
|
|
42
|
+
if (error) {
|
|
43
|
+
logger_1.AppLogger.warn(`OAuth error: ${error} - ${error_description}`);
|
|
44
|
+
res.status(400).json({
|
|
45
|
+
success: false,
|
|
46
|
+
error: error,
|
|
47
|
+
message: error_description,
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!code || !state) {
|
|
52
|
+
logger_1.AppLogger.warn('OAuth callback missing code or state');
|
|
53
|
+
res.status(400).json({
|
|
54
|
+
success: false,
|
|
55
|
+
error: 'Missing parameters',
|
|
56
|
+
message: 'OAuth code and state are required',
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const result = await (0, auth_service_1.handleOAuthCallback)(code, state);
|
|
61
|
+
res.json({
|
|
62
|
+
success: true,
|
|
63
|
+
message: 'Authentication successful',
|
|
64
|
+
...result,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
logger_1.AppLogger.error(`OAuth callback failed: ${error}`);
|
|
69
|
+
const message = error instanceof Error ? error.message : 'Failed to complete GitHub OAuth flow';
|
|
70
|
+
if (message.includes('CSRF')) {
|
|
71
|
+
res.status(400).json({
|
|
72
|
+
success: false,
|
|
73
|
+
error: 'Invalid state',
|
|
74
|
+
message,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
res.status(500).json({
|
|
79
|
+
success: false,
|
|
80
|
+
error: 'Authentication failed',
|
|
81
|
+
message,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
exports.callback = callback;
|
|
87
|
+
/**
|
|
88
|
+
* Get current user session
|
|
89
|
+
* GET /auth/me
|
|
90
|
+
*/
|
|
91
|
+
const me = (req, res) => {
|
|
92
|
+
try {
|
|
93
|
+
const session = (0, auth_service_1.getCurrentSession)(req);
|
|
94
|
+
res.json({
|
|
95
|
+
success: true,
|
|
96
|
+
...session,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
logger_1.AppLogger.error(`Failed to get user session: ${error}`);
|
|
101
|
+
res.status(401).json({
|
|
102
|
+
success: false,
|
|
103
|
+
error: 'Unauthorized',
|
|
104
|
+
message: error instanceof Error ? error.message : 'Failed to retrieve user information',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
exports.me = me;
|
|
109
|
+
/**
|
|
110
|
+
* Validate session
|
|
111
|
+
* POST /auth/validate
|
|
112
|
+
*/
|
|
113
|
+
const validate = async (req, res) => {
|
|
114
|
+
try {
|
|
115
|
+
const result = await (0, auth_service_1.validateCurrentSession)(req);
|
|
116
|
+
res.json({
|
|
117
|
+
success: true,
|
|
118
|
+
...result,
|
|
119
|
+
message: 'Session is valid',
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
logger_1.AppLogger.error(`Session validation failed: ${error}`);
|
|
124
|
+
if (error instanceof Error && error.message.includes('no longer valid')) {
|
|
125
|
+
res.status(401).json({
|
|
126
|
+
success: false,
|
|
127
|
+
valid: false,
|
|
128
|
+
error: 'Unauthorized',
|
|
129
|
+
message: error.message,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
res.status(500).json({
|
|
134
|
+
success: false,
|
|
135
|
+
valid: false,
|
|
136
|
+
error: 'Validation failed',
|
|
137
|
+
message: error instanceof Error ? error.message : 'Failed to validate session',
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
exports.validate = validate;
|
|
143
|
+
/**
|
|
144
|
+
* Logout
|
|
145
|
+
* POST /auth/logout
|
|
146
|
+
*/
|
|
147
|
+
const logout = (req, res) => {
|
|
148
|
+
try {
|
|
149
|
+
(0, auth_service_1.logoutUser)(req);
|
|
150
|
+
res.json({
|
|
151
|
+
success: true,
|
|
152
|
+
message: 'Logout successful',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
logger_1.AppLogger.error(`Logout failed: ${error}`);
|
|
157
|
+
res.status(500).json({
|
|
158
|
+
success: false,
|
|
159
|
+
error: 'Logout failed',
|
|
160
|
+
message: error instanceof Error ? error.message : 'Failed to logout',
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
exports.logout = logout;
|
|
165
|
+
/**
|
|
166
|
+
* Refresh session (token)
|
|
167
|
+
* POST /auth/refresh
|
|
168
|
+
*/
|
|
169
|
+
const refresh = async (req, res) => {
|
|
170
|
+
try {
|
|
171
|
+
const result = await (0, auth_service_1.refreshUserSession)(req);
|
|
172
|
+
res.json({
|
|
173
|
+
success: true,
|
|
174
|
+
message: 'Session refreshed successfully',
|
|
175
|
+
...result,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
logger_1.AppLogger.error(`Session refresh failed: ${error}`);
|
|
180
|
+
if (error instanceof Error && error.message.includes('no longer valid')) {
|
|
181
|
+
res.status(401).json({
|
|
182
|
+
success: false,
|
|
183
|
+
error: 'Unauthorized',
|
|
184
|
+
message: error.message,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
res.status(500).json({
|
|
189
|
+
success: false,
|
|
190
|
+
error: 'Refresh failed',
|
|
191
|
+
message: error instanceof Error ? error.message : 'Failed to refresh session',
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
exports.refresh = refresh;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Permission Controller
|
|
4
|
+
* Thin controller that handles HTTP concerns and delegates business logic to permission-service
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.invalidateCache = exports.checkActionPermission = exports.getRepositoryPermission = void 0;
|
|
8
|
+
const auth_middleware_1 = require("../middleware/auth-middleware");
|
|
9
|
+
const permission_service_1 = require("../services/permission-service");
|
|
10
|
+
const logger_1 = require("../middleware/logger");
|
|
11
|
+
/**
|
|
12
|
+
* Get user's permission for a specific repository
|
|
13
|
+
* GET /permissions/:owner/:repo
|
|
14
|
+
*/
|
|
15
|
+
const getRepositoryPermission = async (req, res) => {
|
|
16
|
+
try {
|
|
17
|
+
const session = (0, auth_middleware_1.getSessionFromRequest)(req);
|
|
18
|
+
if (!session) {
|
|
19
|
+
res.status(401).json({
|
|
20
|
+
success: false,
|
|
21
|
+
error: 'Unauthorized',
|
|
22
|
+
message: 'No active session',
|
|
23
|
+
});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const { owner, repo } = req.params;
|
|
27
|
+
const forceRefresh = req.query.refresh === 'true';
|
|
28
|
+
if (!owner || !repo) {
|
|
29
|
+
res.status(400).json({
|
|
30
|
+
success: false,
|
|
31
|
+
error: 'Bad request',
|
|
32
|
+
message: 'Owner and repo parameters are required',
|
|
33
|
+
});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
logger_1.AppLogger.debug(`Checking permission for ${session.user.login} in ${owner}/${repo}`);
|
|
37
|
+
const permissionCheck = await (0, permission_service_1.checkRepositoryPermission)(session.accessToken, session.user.id, session.user.login, owner, repo, forceRefresh);
|
|
38
|
+
res.json({
|
|
39
|
+
success: true,
|
|
40
|
+
owner,
|
|
41
|
+
repo,
|
|
42
|
+
user: session.user.login,
|
|
43
|
+
...permissionCheck,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
logger_1.AppLogger.error(`Failed to check permission: ${error}`);
|
|
48
|
+
res.status(500).json({
|
|
49
|
+
success: false,
|
|
50
|
+
error: 'Internal server error',
|
|
51
|
+
message: 'Failed to check repository permission',
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
exports.getRepositoryPermission = getRepositoryPermission;
|
|
56
|
+
/**
|
|
57
|
+
* Check if user can perform a specific action
|
|
58
|
+
* POST /permissions/:owner/:repo/can-action
|
|
59
|
+
*/
|
|
60
|
+
const checkActionPermission = async (req, res) => {
|
|
61
|
+
try {
|
|
62
|
+
const session = (0, auth_middleware_1.getSessionFromRequest)(req);
|
|
63
|
+
if (!session) {
|
|
64
|
+
res.status(401).json({
|
|
65
|
+
success: false,
|
|
66
|
+
error: 'Unauthorized',
|
|
67
|
+
message: 'No active session',
|
|
68
|
+
});
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const { owner, repo } = req.params;
|
|
72
|
+
const { action } = req.body;
|
|
73
|
+
if (!owner || !repo) {
|
|
74
|
+
res.status(400).json({
|
|
75
|
+
success: false,
|
|
76
|
+
error: 'Bad request',
|
|
77
|
+
message: 'Owner and repo parameters are required',
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (!action || !['read', 'write', 'maintain', 'admin'].includes(action)) {
|
|
82
|
+
res.status(400).json({
|
|
83
|
+
success: false,
|
|
84
|
+
error: 'Bad request',
|
|
85
|
+
message: 'Valid action is required (read, write, maintain, or admin)',
|
|
86
|
+
});
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
logger_1.AppLogger.debug(`Checking if ${session.user.login} can perform '${action}' in ${owner}/${repo}`);
|
|
90
|
+
const actionCheck = await (0, permission_service_1.checkUserAction)(session.accessToken, session.user.id, session.user.login, owner, repo, action);
|
|
91
|
+
res.json({
|
|
92
|
+
success: true,
|
|
93
|
+
owner,
|
|
94
|
+
repo,
|
|
95
|
+
user: session.user.login,
|
|
96
|
+
...actionCheck,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
logger_1.AppLogger.error(`Failed to check action permission: ${error}`);
|
|
101
|
+
res.status(500).json({
|
|
102
|
+
success: false,
|
|
103
|
+
error: 'Internal server error',
|
|
104
|
+
message: 'Failed to check action permission',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
exports.checkActionPermission = checkActionPermission;
|
|
109
|
+
/**
|
|
110
|
+
* Invalidate permission cache for a repository
|
|
111
|
+
* POST /permissions/:owner/:repo/invalidate
|
|
112
|
+
*/
|
|
113
|
+
const invalidateCache = (req, res) => {
|
|
114
|
+
try {
|
|
115
|
+
const session = (0, auth_middleware_1.getSessionFromRequest)(req);
|
|
116
|
+
if (!session) {
|
|
117
|
+
res.status(401).json({
|
|
118
|
+
success: false,
|
|
119
|
+
error: 'Unauthorized',
|
|
120
|
+
message: 'No active session',
|
|
121
|
+
});
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const { owner, repo } = req.params;
|
|
125
|
+
if (!owner || !repo) {
|
|
126
|
+
res.status(400).json({
|
|
127
|
+
success: false,
|
|
128
|
+
error: 'Bad request',
|
|
129
|
+
message: 'Owner and repo parameters are required',
|
|
130
|
+
});
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
logger_1.AppLogger.debug(`Invalidating permission cache for ${session.user.login} in ${owner}/${repo}`);
|
|
134
|
+
(0, permission_service_1.invalidatePermissionCache)(session.user.id, owner, repo);
|
|
135
|
+
res.json({
|
|
136
|
+
success: true,
|
|
137
|
+
message: 'Permission cache invalidated',
|
|
138
|
+
owner,
|
|
139
|
+
repo,
|
|
140
|
+
user: session.user.login,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
logger_1.AppLogger.error(`Failed to invalidate cache: ${error}`);
|
|
145
|
+
res.status(500).json({
|
|
146
|
+
success: false,
|
|
147
|
+
error: 'Internal server error',
|
|
148
|
+
message: 'Failed to invalidate permission cache',
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
exports.invalidateCache = invalidateCache;
|