streamby-core 0.32.1 → 0.34.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/CHANGELOG.md +67 -0
- package/LICENSE +661 -0
- package/README.md +53 -2
- package/dist/middleware/createRouter.js +17 -2
- package/dist/middleware/routes/ai.js +3 -3
- package/dist/middleware/routes/connection.js +3 -12
- package/dist/middleware/routes/dbConnection.js +7 -26
- package/dist/middleware/routes/distribution.js +12 -5
- package/dist/middleware/routes/export.js +5 -4
- package/dist/middleware/routes/media.js +23 -10
- package/dist/middleware/routes/member.js +3 -12
- package/dist/middleware/routes/{credential.d.ts → oauth.d.ts} +1 -1
- package/dist/middleware/routes/oauth.js +101 -0
- package/dist/middleware/routes/pipeline.js +3 -3
- package/dist/middleware/routes/production.js +9 -9
- package/dist/middleware/routes/project.js +24 -31
- package/dist/middleware/routes/renderFarm.js +13 -6
- package/dist/middleware/routes/review.js +4 -4
- package/dist/middleware/routes/rights.js +1 -1
- package/dist/middleware/routes/storage.js +21 -15
- package/dist/middleware/routes/storageConnection.js +2 -8
- package/dist/middleware/routes/userIntegration.js +17 -2
- package/dist/middleware/routes/workflow.js +1 -1
- package/dist/services/auth.d.ts +1 -2
- package/dist/services/auth.js +9 -11
- package/dist/services/connectionResolver.js +6 -6
- package/dist/services/executor.d.ts +4 -1
- package/dist/services/executor.js +63 -6
- package/dist/services/oauthClient.d.ts +10 -0
- package/dist/services/oauthClient.js +134 -0
- package/dist/services/projectIntegration.d.ts +4 -1
- package/dist/services/projectIntegration.js +13 -3
- package/dist/services/reencryptCredentials.d.ts +5 -0
- package/dist/services/reencryptCredentials.js +74 -0
- package/dist/services/userIntegration.d.ts +23 -3
- package/dist/services/userIntegration.js +130 -7
- package/dist/types/index.d.ts +31 -3
- package/dist/utils/auth.d.ts +15 -1
- package/dist/utils/auth.js +21 -6
- package/dist/utils/encryption.d.ts +6 -1
- package/dist/utils/encryption.js +80 -27
- package/dist/utils/sanitize.d.ts +6 -0
- package/dist/utils/sanitize.js +18 -1
- package/dist/utils/serviceEndpoints.d.ts +2 -0
- package/dist/utils/serviceEndpoints.js +26 -0
- package/package.json +4 -3
- package/dist/middleware/routes/apiConnection.d.ts +0 -3
- package/dist/middleware/routes/apiConnection.js +0 -100
- package/dist/middleware/routes/credential.js +0 -80
- package/dist/services/apiConnection.d.ts +0 -18
- package/dist/services/apiConnection.js +0 -65
- package/dist/services/credential.d.ts +0 -8
- package/dist/services/credential.js +0 -70
- package/dist/services/pipeline.d.ts +0 -2
- package/dist/services/pipeline.js +0 -292
|
@@ -0,0 +1,101 @@
|
|
|
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.oauthRouter = oauthRouter;
|
|
7
|
+
const express_1 = require("express");
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const oauthClient_1 = require("../../services/oauthClient");
|
|
10
|
+
const userIntegration_1 = require("../../services/userIntegration");
|
|
11
|
+
const OAUTH_PROVIDERS = new Set(['jira', 'google']);
|
|
12
|
+
const PROVIDER_DISPLAY_NAME = {
|
|
13
|
+
jira: 'Jira',
|
|
14
|
+
google: 'Google',
|
|
15
|
+
};
|
|
16
|
+
// In-memory, single-process state store — the OAuth dance completes within a few minutes
|
|
17
|
+
// of the same request cycle, so no DB collection is needed. A restart mid-flow just means
|
|
18
|
+
// the user retries /start, which is harmless.
|
|
19
|
+
const pendingOAuthStates = new Map();
|
|
20
|
+
const STATE_TTL_MS = 10 * 60 * 1000;
|
|
21
|
+
function sweepExpiredStates() {
|
|
22
|
+
const cutoff = Date.now() - STATE_TTL_MS;
|
|
23
|
+
for (const [state, entry] of pendingOAuthStates) {
|
|
24
|
+
if (entry.issuedAt < cutoff)
|
|
25
|
+
pendingOAuthStates.delete(state);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function isOAuthProvider(value) {
|
|
29
|
+
return OAUTH_PROVIDERS.has(value);
|
|
30
|
+
}
|
|
31
|
+
function oauthRouter(config) {
|
|
32
|
+
const router = (0, express_1.Router)();
|
|
33
|
+
router.get('/user/integrations/oauth/:provider/start', async (req, res) => {
|
|
34
|
+
try {
|
|
35
|
+
const auth = req.auth;
|
|
36
|
+
const { provider } = req.params;
|
|
37
|
+
if (!isOAuthProvider(provider)) {
|
|
38
|
+
return res.status(400).json({ message: `Provider '${provider}' does not support OAuth.` });
|
|
39
|
+
}
|
|
40
|
+
const oauthConfig = config.oauthProviders?.[provider];
|
|
41
|
+
if (!oauthConfig) {
|
|
42
|
+
return res.status(503).json({ message: `OAuth for '${provider}' is not configured on this deployment.` });
|
|
43
|
+
}
|
|
44
|
+
sweepExpiredStates();
|
|
45
|
+
const state = crypto_1.default.randomBytes(32).toString('hex');
|
|
46
|
+
pendingOAuthStates.set(state, { userId: auth.userId, provider, issuedAt: Date.now() });
|
|
47
|
+
res.redirect((0, oauthClient_1.buildAuthorizeUrl)(provider, oauthConfig, state));
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
res.status(500).json({ message: 'Failed to start OAuth flow', details: err.message });
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
router.get('/user/integrations/oauth/:provider/callback', async (req, res) => {
|
|
54
|
+
const { provider: providerParam } = req.params;
|
|
55
|
+
const provider = isOAuthProvider(providerParam) ? providerParam : null;
|
|
56
|
+
const oauthConfig = provider ? config.oauthProviders?.[provider] : undefined;
|
|
57
|
+
const failureRedirect = (reason) => {
|
|
58
|
+
const failureUrl = oauthConfig?.failureRedirectUrl;
|
|
59
|
+
if (!failureUrl)
|
|
60
|
+
return res.status(400).json({ message: `OAuth failed: ${reason}` });
|
|
61
|
+
const url = new URL(failureUrl);
|
|
62
|
+
url.searchParams.set('oauthError', reason);
|
|
63
|
+
if (provider)
|
|
64
|
+
url.searchParams.set('provider', provider);
|
|
65
|
+
return res.redirect(url.toString());
|
|
66
|
+
};
|
|
67
|
+
try {
|
|
68
|
+
const auth = req.auth;
|
|
69
|
+
if (!provider)
|
|
70
|
+
return res.status(400).json({ message: `Provider '${providerParam}' does not support OAuth.` });
|
|
71
|
+
if (!oauthConfig)
|
|
72
|
+
return res.status(503).json({ message: `OAuth for '${provider}' is not configured on this deployment.` });
|
|
73
|
+
if (req.query.error)
|
|
74
|
+
return failureRedirect(String(req.query.error));
|
|
75
|
+
const code = req.query.code;
|
|
76
|
+
const state = req.query.state;
|
|
77
|
+
if (!code || !state)
|
|
78
|
+
return failureRedirect('missing_code');
|
|
79
|
+
const pending = pendingOAuthStates.get(state);
|
|
80
|
+
pendingOAuthStates.delete(state); // single-use, regardless of outcome below
|
|
81
|
+
if (!pending || pending.provider !== provider || pending.userId !== auth.userId) {
|
|
82
|
+
return failureRedirect(pending ? 'state_mismatch' : 'invalid_state');
|
|
83
|
+
}
|
|
84
|
+
let tokens;
|
|
85
|
+
try {
|
|
86
|
+
tokens = await (0, oauthClient_1.exchangeCodeForTokens)(provider, oauthConfig, code);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return failureRedirect('token_exchange_failed');
|
|
90
|
+
}
|
|
91
|
+
await (0, userIntegration_1.upsertOAuthServiceIntegration)(auth.userId, provider, PROVIDER_DISPLAY_NAME[provider], tokens);
|
|
92
|
+
const url = new URL(oauthConfig.successRedirectUrl);
|
|
93
|
+
url.searchParams.set('connected', provider);
|
|
94
|
+
res.redirect(url.toString());
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
failureRedirect('unexpected_error');
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return router;
|
|
101
|
+
}
|
|
@@ -67,7 +67,7 @@ function pipelineRouter(_config) {
|
|
|
67
67
|
const project = await Project.findOne({ _id: projectId });
|
|
68
68
|
if (!project)
|
|
69
69
|
return res.status(404).json({ message: 'Project not found' });
|
|
70
|
-
if (!(0, auth_1.
|
|
70
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
71
71
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
72
72
|
const db = getDb();
|
|
73
73
|
if (!db)
|
|
@@ -120,7 +120,7 @@ function pipelineRouter(_config) {
|
|
|
120
120
|
const project = await Project.findOne({ _id: projectId });
|
|
121
121
|
if (!project)
|
|
122
122
|
return res.status(404).json({ message: 'Project not found' });
|
|
123
|
-
if (!(0, auth_1.
|
|
123
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
124
124
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
125
125
|
const db = getDb();
|
|
126
126
|
if (!db)
|
|
@@ -154,7 +154,7 @@ function pipelineRouter(_config) {
|
|
|
154
154
|
const project = await Project.findOne({ _id: projectId });
|
|
155
155
|
if (!project)
|
|
156
156
|
return res.status(404).json({ message: 'Project not found' });
|
|
157
|
-
if (!(0, auth_1.
|
|
157
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
158
158
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
159
159
|
const db = getDb();
|
|
160
160
|
if (!db)
|
|
@@ -51,7 +51,7 @@ function productionRouter(_config) {
|
|
|
51
51
|
const project = await Project.findOne({ _id: projectId });
|
|
52
52
|
if (!project)
|
|
53
53
|
return res.status(404).json({ message: 'Project not found' });
|
|
54
|
-
if (!(0, auth_1.
|
|
54
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
55
55
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
56
56
|
const db = getDb();
|
|
57
57
|
if (!db)
|
|
@@ -81,7 +81,7 @@ function productionRouter(_config) {
|
|
|
81
81
|
const project = await Project.findOne({ _id: projectId });
|
|
82
82
|
if (!project)
|
|
83
83
|
return res.status(404).json({ message: 'Project not found' });
|
|
84
|
-
if (!(0, auth_1.
|
|
84
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
85
85
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
86
86
|
const db = getDb();
|
|
87
87
|
if (!db)
|
|
@@ -110,7 +110,7 @@ function productionRouter(_config) {
|
|
|
110
110
|
const project = await Project.findOne({ _id: projectId });
|
|
111
111
|
if (!project)
|
|
112
112
|
return res.status(404).json({ message: 'Project not found' });
|
|
113
|
-
if (!(0, auth_1.
|
|
113
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
114
114
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
115
115
|
const db = getDb();
|
|
116
116
|
if (!db)
|
|
@@ -156,7 +156,7 @@ function productionRouter(_config) {
|
|
|
156
156
|
const project = await Project.findOne({ _id: projectId });
|
|
157
157
|
if (!project)
|
|
158
158
|
return res.status(404).json({ message: 'Project not found' });
|
|
159
|
-
if (!(0, auth_1.
|
|
159
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
160
160
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
161
161
|
const db = getDb();
|
|
162
162
|
if (!db)
|
|
@@ -192,7 +192,7 @@ function productionRouter(_config) {
|
|
|
192
192
|
const project = await Project.findOne({ _id: projectId });
|
|
193
193
|
if (!project)
|
|
194
194
|
return res.status(404).json({ message: 'Project not found' });
|
|
195
|
-
if (!(0, auth_1.
|
|
195
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
196
196
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
197
197
|
const db = getDb();
|
|
198
198
|
if (!db)
|
|
@@ -231,7 +231,7 @@ function productionRouter(_config) {
|
|
|
231
231
|
const project = await Project.findOne({ _id: projectId });
|
|
232
232
|
if (!project)
|
|
233
233
|
return res.status(404).json({ message: 'Project not found' });
|
|
234
|
-
if (!(0, auth_1.
|
|
234
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
235
235
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
236
236
|
const db = getDb();
|
|
237
237
|
if (!db)
|
|
@@ -277,7 +277,7 @@ function productionRouter(_config) {
|
|
|
277
277
|
const project = await Project.findOne({ _id: projectId });
|
|
278
278
|
if (!project)
|
|
279
279
|
return res.status(404).json({ message: 'Project not found' });
|
|
280
|
-
if (!(0, auth_1.
|
|
280
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
281
281
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
282
282
|
const db = getDb();
|
|
283
283
|
if (!db)
|
|
@@ -311,7 +311,7 @@ function productionRouter(_config) {
|
|
|
311
311
|
const project = await Project.findOne({ _id: projectId });
|
|
312
312
|
if (!project)
|
|
313
313
|
return res.status(404).json({ message: 'Project not found' });
|
|
314
|
-
if (!(0, auth_1.
|
|
314
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
315
315
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
316
316
|
const db = getDb();
|
|
317
317
|
if (!db)
|
|
@@ -346,7 +346,7 @@ function productionRouter(_config) {
|
|
|
346
346
|
const project = await Project.findOne({ _id: projectId });
|
|
347
347
|
if (!project)
|
|
348
348
|
return res.status(404).json({ message: 'Project not found' });
|
|
349
|
-
if (!(0, auth_1.
|
|
349
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
350
350
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
351
351
|
const db = getDb();
|
|
352
352
|
if (!db)
|
|
@@ -72,9 +72,6 @@ function projectRouter(config) {
|
|
|
72
72
|
if (req.subscription === 'freemium') {
|
|
73
73
|
return res.status(403).json({ error: 'Freemium users cannot create projects' });
|
|
74
74
|
}
|
|
75
|
-
if (auth.role !== 'admin' && auth.role !== 'editor') {
|
|
76
|
-
return res.status(403).json({ message: 'Permission denied' });
|
|
77
|
-
}
|
|
78
75
|
const { name, description, image, allowedOrigin, public: isPublic = true, category, integrationIds } = req.body;
|
|
79
76
|
if (isPublic === false && req.subscription === 'freemium') {
|
|
80
77
|
return res.status(403).json({ error: 'Private projects require a subscriber plan' });
|
|
@@ -93,6 +90,7 @@ function projectRouter(config) {
|
|
|
93
90
|
// builtin id. Any invalid id rejects the whole request (no project is created).
|
|
94
91
|
const dbConnections = [];
|
|
95
92
|
const storageConnections = [];
|
|
93
|
+
const integrationConnections = [];
|
|
96
94
|
if (Array.isArray(integrationIds)) {
|
|
97
95
|
for (const id of integrationIds) {
|
|
98
96
|
const result = await (0, projectIntegration_1.classifyIntegrationId)(id, auth, config, '');
|
|
@@ -100,8 +98,10 @@ function projectRouter(config) {
|
|
|
100
98
|
return res.status(result.status).json({ message: result.error });
|
|
101
99
|
if (result.kind === 'database')
|
|
102
100
|
dbConnections.push(result.connection);
|
|
103
|
-
else
|
|
101
|
+
else if (result.kind === 'storage')
|
|
104
102
|
storageConnections.push(result.connection);
|
|
103
|
+
else
|
|
104
|
+
integrationConnections.push(result.connection);
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
let newProject = await Project.create({
|
|
@@ -115,12 +115,14 @@ function projectRouter(config) {
|
|
|
115
115
|
members: [{ userId: auth.userId, username: user.username, role: "admin", status: "active", archived: false }],
|
|
116
116
|
dbConnections: [],
|
|
117
117
|
storageConnections: [],
|
|
118
|
+
integrationConnections: [],
|
|
118
119
|
});
|
|
119
120
|
const newProjectId = newProject._id || newProject.id;
|
|
120
|
-
if (dbConnections.length || storageConnections.length) {
|
|
121
|
+
if (dbConnections.length || storageConnections.length || integrationConnections.length) {
|
|
121
122
|
const stamped = await Project.update({ _id: newProjectId }, {
|
|
122
123
|
dbConnections: dbConnections.map(c => ({ ...c, projectId: newProjectId })),
|
|
123
124
|
storageConnections: storageConnections.map(c => ({ ...c, projectId: newProjectId })),
|
|
125
|
+
integrationConnections: integrationConnections.map(c => ({ ...c, projectId: newProjectId })),
|
|
124
126
|
});
|
|
125
127
|
if (stamped)
|
|
126
128
|
newProject = stamped;
|
|
@@ -203,9 +205,6 @@ function projectRouter(config) {
|
|
|
203
205
|
router.patch('/projects/:id', async (req, res) => {
|
|
204
206
|
try {
|
|
205
207
|
const auth = req.auth;
|
|
206
|
-
if (auth.role !== 'admin' && auth.role !== 'editor') {
|
|
207
|
-
return res.status(403).json({ message: 'Permission denied' });
|
|
208
|
-
}
|
|
209
208
|
const projectId = req.params.id;
|
|
210
209
|
const updates = req.body;
|
|
211
210
|
const project = await Project.findOne({ _id: projectId });
|
|
@@ -215,7 +214,7 @@ function projectRouter(config) {
|
|
|
215
214
|
if (!updates || typeof updates !== 'object') {
|
|
216
215
|
return res.status(400).json({ message: 'Missing updates payload' });
|
|
217
216
|
}
|
|
218
|
-
if (!(0, auth_1.
|
|
217
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId)) {
|
|
219
218
|
return res.status(403).json({ message: 'Unauthorized project access' });
|
|
220
219
|
}
|
|
221
220
|
const updated = await Project.update({ _id: projectId }, updates);
|
|
@@ -245,8 +244,9 @@ function projectRouter(config) {
|
|
|
245
244
|
if (!project) {
|
|
246
245
|
return res.status(404).json({ message: 'Project not found' });
|
|
247
246
|
}
|
|
248
|
-
|
|
249
|
-
|
|
247
|
+
// Only an admin of the project deletes it.
|
|
248
|
+
if (!(0, auth_1.isProjectAdmin)(project, auth.userId)) {
|
|
249
|
+
return res.status(403).json({ message: 'Only a project admin can delete it' });
|
|
250
250
|
}
|
|
251
251
|
await Project.useDbType(project.dbType).delete({ _id: projectId });
|
|
252
252
|
const allProjects = await Project.find({});
|
|
@@ -343,9 +343,6 @@ function projectRouter(config) {
|
|
|
343
343
|
router.post('/projects/:id/image', async (req, res) => {
|
|
344
344
|
try {
|
|
345
345
|
const auth = req.auth;
|
|
346
|
-
if (auth.role !== 'admin' && auth.role !== 'editor') {
|
|
347
|
-
return res.status(403).json({ message: 'Permission denied' });
|
|
348
|
-
}
|
|
349
346
|
const projectId = req.params.id;
|
|
350
347
|
const { imageUrl } = req.body;
|
|
351
348
|
if (!projectId || !imageUrl) {
|
|
@@ -355,7 +352,7 @@ function projectRouter(config) {
|
|
|
355
352
|
if (!project) {
|
|
356
353
|
return res.status(404).json({ message: 'Project not found' });
|
|
357
354
|
}
|
|
358
|
-
if (!(0, auth_1.
|
|
355
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId)) {
|
|
359
356
|
return res.status(403).json({ message: 'Unauthorized project access' });
|
|
360
357
|
}
|
|
361
358
|
const updatedProject = await Project.update({ _id: projectId }, { image: imageUrl });
|
|
@@ -371,16 +368,13 @@ function projectRouter(config) {
|
|
|
371
368
|
router.patch('/projects/:id/origins', async (req, res) => {
|
|
372
369
|
try {
|
|
373
370
|
const auth = req.auth;
|
|
374
|
-
if (auth.role !== 'admin' && auth.role !== 'editor') {
|
|
375
|
-
return res.status(403).json({ message: 'Permission denied' });
|
|
376
|
-
}
|
|
377
371
|
const projectId = req.params.id;
|
|
378
372
|
const { origins } = req.body;
|
|
379
373
|
const project = await Project.findOne({ _id: projectId });
|
|
380
374
|
if (!project) {
|
|
381
375
|
return res.status(404).json({ message: 'Project not found' });
|
|
382
376
|
}
|
|
383
|
-
if (!(0, auth_1.
|
|
377
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId)) {
|
|
384
378
|
return res.status(403).json({ message: 'Unauthorized project access' });
|
|
385
379
|
}
|
|
386
380
|
const updated = await Project.update({ _id: projectId }, { allowedOrigin: origins });
|
|
@@ -397,9 +391,6 @@ function projectRouter(config) {
|
|
|
397
391
|
router.post('/projects/:id/integrations', async (req, res) => {
|
|
398
392
|
try {
|
|
399
393
|
const auth = req.auth;
|
|
400
|
-
if (auth.role !== 'admin' && auth.role !== 'editor') {
|
|
401
|
-
return res.status(403).json({ message: 'Permission denied' });
|
|
402
|
-
}
|
|
403
394
|
const projectId = req.params.id;
|
|
404
395
|
const { integrationId } = req.body;
|
|
405
396
|
if (!integrationId)
|
|
@@ -407,9 +398,9 @@ function projectRouter(config) {
|
|
|
407
398
|
const project = await Project.findOne({ _id: projectId });
|
|
408
399
|
if (!project)
|
|
409
400
|
return res.status(404).json({ message: 'Project not found' });
|
|
410
|
-
if (!(0, auth_1.
|
|
401
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
411
402
|
return res.status(403).json({ message: 'Unauthorized project access' });
|
|
412
|
-
const alreadyConnected = [...(project.dbConnections ?? []), ...(project.storageConnections ?? [])]
|
|
403
|
+
const alreadyConnected = [...(project.dbConnections ?? []), ...(project.storageConnections ?? []), ...(project.integrationConnections ?? [])]
|
|
413
404
|
.some((c) => c.integrationId === integrationId);
|
|
414
405
|
if (alreadyConnected)
|
|
415
406
|
return res.status(400).json({ message: 'This integration is already connected to the project' });
|
|
@@ -418,7 +409,9 @@ function projectRouter(config) {
|
|
|
418
409
|
return res.status(result.status).json({ message: result.error });
|
|
419
410
|
const updated = result.kind === 'database'
|
|
420
411
|
? await Project.update({ _id: projectId }, { $push: { dbConnections: result.connection } })
|
|
421
|
-
:
|
|
412
|
+
: result.kind === 'storage'
|
|
413
|
+
? await Project.update({ _id: projectId }, { $push: { storageConnections: result.connection } })
|
|
414
|
+
: await Project.update({ _id: projectId }, { $push: { integrationConnections: result.connection } });
|
|
422
415
|
if (!updated)
|
|
423
416
|
return res.status(404).json({ message: 'Project not found or not updated' });
|
|
424
417
|
res.status(201).json({ data: result.connection, project: (0, sanitize_1.sanitizeProject)(updated) });
|
|
@@ -431,23 +424,23 @@ function projectRouter(config) {
|
|
|
431
424
|
router.delete('/projects/:id/integrations/:integrationId', async (req, res) => {
|
|
432
425
|
try {
|
|
433
426
|
const auth = req.auth;
|
|
434
|
-
if (auth.role !== 'admin' && auth.role !== 'editor') {
|
|
435
|
-
return res.status(403).json({ message: 'Permission denied' });
|
|
436
|
-
}
|
|
437
427
|
const projectId = req.params.id;
|
|
438
428
|
const { integrationId } = req.params;
|
|
439
429
|
const project = await Project.findOne({ _id: projectId });
|
|
440
430
|
if (!project)
|
|
441
431
|
return res.status(404).json({ message: 'Project not found' });
|
|
442
|
-
if (!(0, auth_1.
|
|
432
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
443
433
|
return res.status(403).json({ message: 'Unauthorized project access' });
|
|
444
434
|
const dbConn = (project.dbConnections ?? []).find((c) => c.integrationId === integrationId);
|
|
445
435
|
const storageConn = (project.storageConnections ?? []).find((c) => c.integrationId === integrationId);
|
|
446
|
-
|
|
436
|
+
const integrationConn = (project.integrationConnections ?? []).find((c) => c.integrationId === integrationId);
|
|
437
|
+
if (!dbConn && !storageConn && !integrationConn)
|
|
447
438
|
return res.status(404).json({ message: 'Integration not connected to this project' });
|
|
448
439
|
const updated = dbConn
|
|
449
440
|
? await Project.update({ _id: projectId }, { $pull: { dbConnections: { id: dbConn.id } } })
|
|
450
|
-
:
|
|
441
|
+
: storageConn
|
|
442
|
+
? await Project.update({ _id: projectId }, { $pull: { storageConnections: { id: storageConn.id } } })
|
|
443
|
+
: await Project.update({ _id: projectId }, { $pull: { integrationConnections: { id: integrationConn.id } } });
|
|
451
444
|
if (!updated)
|
|
452
445
|
return res.status(404).json({ message: 'Project not found or not updated' });
|
|
453
446
|
res.status(200).json({ message: 'Integration removed', project: (0, sanitize_1.sanitizeProject)(updated) });
|
|
@@ -11,6 +11,7 @@ const jobQueue_1 = require("../../services/jobQueue");
|
|
|
11
11
|
const vfxProcessor_1 = require("../../services/vfxProcessor");
|
|
12
12
|
const sanitize_1 = require("../../utils/sanitize");
|
|
13
13
|
const crypto_1 = __importDefault(require("crypto"));
|
|
14
|
+
const encryption_1 = require("../../utils/encryption");
|
|
14
15
|
function renderFarmRouter(_config) {
|
|
15
16
|
const router = (0, express_1.Router)();
|
|
16
17
|
const Project = (0, manager_1.getModel)('projects');
|
|
@@ -34,14 +35,20 @@ function renderFarmRouter(_config) {
|
|
|
34
35
|
try {
|
|
35
36
|
const auth = req.auth;
|
|
36
37
|
const { projectId } = req.params;
|
|
37
|
-
const { name, provider, apiUrl, encryptedCredential, description } = req.body;
|
|
38
|
+
const { name, provider, apiUrl, credential: credentialValue, encryptedCredential: legacyCredential, description } = req.body;
|
|
39
|
+
// The credential, as given (`encryptedCredential` was its old name: it was always the
|
|
40
|
+
// value itself), stored encrypted.
|
|
41
|
+
const credential = credentialValue ?? legacyCredential;
|
|
42
|
+
if (credential && !(0, encryption_1.isEncryptionKeySet)())
|
|
43
|
+
return res.status(500).json({ message: 'Encryption key is not set' });
|
|
44
|
+
const encryptedCredential = credential ? (0, encryption_1.encrypt)(String(credential)) : undefined;
|
|
38
45
|
if (!name || !provider || !apiUrl) {
|
|
39
46
|
return res.status(400).json({ message: 'name, provider and apiUrl are required' });
|
|
40
47
|
}
|
|
41
48
|
const project = await Project.findOne({ _id: projectId });
|
|
42
49
|
if (!project)
|
|
43
50
|
return res.status(404).json({ message: 'Project not found' });
|
|
44
|
-
if (!(0, auth_1.
|
|
51
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
45
52
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
46
53
|
const connection = {
|
|
47
54
|
id: crypto_1.default.randomUUID(),
|
|
@@ -67,7 +74,7 @@ function renderFarmRouter(_config) {
|
|
|
67
74
|
const project = await Project.findOne({ _id: projectId });
|
|
68
75
|
if (!project)
|
|
69
76
|
return res.status(404).json({ message: 'Project not found' });
|
|
70
|
-
if (!(0, auth_1.
|
|
77
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
71
78
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
72
79
|
await Project.update({ _id: projectId }, { $pull: { renderFarmConnections: { id: connectionId } } });
|
|
73
80
|
res.json({ message: 'Connection deleted' });
|
|
@@ -87,7 +94,7 @@ function renderFarmRouter(_config) {
|
|
|
87
94
|
const project = await Project.findOne({ _id: projectId });
|
|
88
95
|
if (!project)
|
|
89
96
|
return res.status(404).json({ message: 'Project not found' });
|
|
90
|
-
if (!(0, auth_1.
|
|
97
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
91
98
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
92
99
|
const job = (0, jobQueue_1.createJob)('render', auth.userId, projectId, { fileId, renderer, renderFarmConnectionId, frameRange, resolution, samples, outputFormat });
|
|
93
100
|
setImmediate(() => (0, vfxProcessor_1.runRenderJob)(job.jobId, fileId, projectId, { renderer, renderFarmConnectionId, frameRange, resolution, samples, outputFormat }));
|
|
@@ -107,7 +114,7 @@ function renderFarmRouter(_config) {
|
|
|
107
114
|
const project = await Project.findOne({ _id: projectId });
|
|
108
115
|
if (!project)
|
|
109
116
|
return res.status(404).json({ message: 'Project not found' });
|
|
110
|
-
if (!(0, auth_1.
|
|
117
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
111
118
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
112
119
|
const job = (0, jobQueue_1.createJob)('format-convert', auth.userId, projectId, { fileId, inputFormat, outputFormat, applyTransforms, embedTextures });
|
|
113
120
|
setImmediate(() => (0, vfxProcessor_1.runFormatConvertJob)(job.jobId, fileId, projectId, { inputFormat, outputFormat, applyTransforms, embedTextures }));
|
|
@@ -127,7 +134,7 @@ function renderFarmRouter(_config) {
|
|
|
127
134
|
const project = await Project.findOne({ _id: projectId });
|
|
128
135
|
if (!project)
|
|
129
136
|
return res.status(404).json({ message: 'Project not found' });
|
|
130
|
-
if (!(0, auth_1.
|
|
137
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
131
138
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
132
139
|
const job = (0, jobQueue_1.createJob)('lod', auth.userId, projectId, { fileId, levels, reductionRatios, algorithm, outputFormat });
|
|
133
140
|
setImmediate(() => (0, vfxProcessor_1.runLodJob)(job.jobId, fileId, projectId, { levels, reductionRatios, algorithm, outputFormat }));
|
|
@@ -60,7 +60,7 @@ function reviewRouter(_config) {
|
|
|
60
60
|
const project = await Project.findOne({ _id: projectId });
|
|
61
61
|
if (!project)
|
|
62
62
|
return res.status(404).json({ message: 'Project not found' });
|
|
63
|
-
if (!(0, auth_1.
|
|
63
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
64
64
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
65
65
|
const db = getDb();
|
|
66
66
|
if (!db)
|
|
@@ -120,7 +120,7 @@ function reviewRouter(_config) {
|
|
|
120
120
|
const project = await Project.findOne({ _id: projectId });
|
|
121
121
|
if (!project)
|
|
122
122
|
return res.status(404).json({ message: 'Project not found' });
|
|
123
|
-
if (!(0, auth_1.
|
|
123
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
124
124
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
125
125
|
const db = getDb();
|
|
126
126
|
if (!db)
|
|
@@ -190,7 +190,7 @@ function reviewRouter(_config) {
|
|
|
190
190
|
const project = await Project.findOne({ _id: projectId });
|
|
191
191
|
if (!project)
|
|
192
192
|
return res.status(404).json({ message: 'Project not found' });
|
|
193
|
-
if (!(0, auth_1.
|
|
193
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
194
194
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
195
195
|
const db = getDb();
|
|
196
196
|
if (!db)
|
|
@@ -224,7 +224,7 @@ function reviewRouter(_config) {
|
|
|
224
224
|
const project = await Project.findOne({ _id: projectId });
|
|
225
225
|
if (!project)
|
|
226
226
|
return res.status(404).json({ message: 'Project not found' });
|
|
227
|
-
if (!(0, auth_1.
|
|
227
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
228
228
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
229
229
|
const db = getDb();
|
|
230
230
|
if (!db)
|
|
@@ -42,7 +42,7 @@ function rightsRouter(_config) {
|
|
|
42
42
|
const project = await Project.findOne({ _id: projectId });
|
|
43
43
|
if (!project)
|
|
44
44
|
return res.status(404).json({ message: 'Project not found' });
|
|
45
|
-
if (!(0, auth_1.
|
|
45
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
46
46
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
47
47
|
const db = getDb();
|
|
48
48
|
if (!db)
|
|
@@ -71,11 +71,14 @@ function storageRouter(config) {
|
|
|
71
71
|
router.get('/upload-project-image-url/:id', async (req, res) => {
|
|
72
72
|
try {
|
|
73
73
|
const auth = req.auth;
|
|
74
|
-
if (auth.role !== 'admin' && auth.role !== 'editor')
|
|
75
|
-
return res.status(403).json({ message: 'Permission denied' });
|
|
76
74
|
const projectId = req.params.id;
|
|
77
75
|
if (!projectId)
|
|
78
76
|
return res.status(400).json({ message: 'Missing projectId' });
|
|
77
|
+
const project = await Project.findOne({ _id: projectId });
|
|
78
|
+
if (!project)
|
|
79
|
+
return res.status(404).json({ message: 'Project not found' });
|
|
80
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
81
|
+
return res.status(403).json({ message: 'Permission denied' });
|
|
79
82
|
const response = await (0, presign_1.getPresignedProjectImageUrl)(adapter, projectId);
|
|
80
83
|
res.status(200).json({ ...response, message: 'Presigned URL generated successfully' });
|
|
81
84
|
}
|
|
@@ -86,11 +89,14 @@ function storageRouter(config) {
|
|
|
86
89
|
router.delete('/delete-project-image-url/:id', async (req, res) => {
|
|
87
90
|
try {
|
|
88
91
|
const auth = req.auth;
|
|
89
|
-
if (auth.role !== 'admin' && auth.role !== 'editor')
|
|
90
|
-
return res.status(403).json({ message: 'Permission denied' });
|
|
91
92
|
const projectId = req.params.id;
|
|
92
93
|
if (!projectId)
|
|
93
94
|
return res.status(400).json({ message: 'Missing projectId' });
|
|
95
|
+
const project = await Project.findOne({ _id: projectId });
|
|
96
|
+
if (!project)
|
|
97
|
+
return res.status(404).json({ message: 'Project not found' });
|
|
98
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
99
|
+
return res.status(403).json({ message: 'Permission denied' });
|
|
94
100
|
await (0, file_1.deleteProjectImage)(adapter, projectId);
|
|
95
101
|
const updated = await Project.update({ _id: projectId }, { image: '' });
|
|
96
102
|
res.status(201).json({ ...updated, message: 'Image deleted successfully' });
|
|
@@ -119,7 +125,7 @@ function storageRouter(config) {
|
|
|
119
125
|
const project = await Project.findOne({ _id: projectId });
|
|
120
126
|
if (!project)
|
|
121
127
|
return res.status(404).json({ message: 'Project not found' });
|
|
122
|
-
if (!(0, auth_1.
|
|
128
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
123
129
|
return res.status(403).json({ message: 'Unauthorized access' });
|
|
124
130
|
if (!adapter.getPresignedUploadUrl) {
|
|
125
131
|
return res.status(501).json({ message: 'Storage adapter does not support presigned uploads' });
|
|
@@ -192,7 +198,7 @@ function storageRouter(config) {
|
|
|
192
198
|
const project = await Project.findOne({ _id: projectId });
|
|
193
199
|
if (!project)
|
|
194
200
|
return res.status(404).json({ message: 'Project not found' });
|
|
195
|
-
if (!(0, auth_1.
|
|
201
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
196
202
|
return res.status(403).json({ message: 'Unauthorized access' });
|
|
197
203
|
const collection = getRawFilesCollection();
|
|
198
204
|
if (!collection)
|
|
@@ -213,7 +219,7 @@ function storageRouter(config) {
|
|
|
213
219
|
const project = await Project.findOne({ _id: projectId });
|
|
214
220
|
if (!project)
|
|
215
221
|
return res.status(404).json({ message: 'Project not found' });
|
|
216
|
-
if (!(0, auth_1.
|
|
222
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
217
223
|
return res.status(403).json({ message: 'Unauthorized access' });
|
|
218
224
|
const collection = getRawFilesCollection();
|
|
219
225
|
if (!collection)
|
|
@@ -291,7 +297,7 @@ function storageRouter(config) {
|
|
|
291
297
|
const project = await Project.findOne({ _id: projectId });
|
|
292
298
|
if (!project)
|
|
293
299
|
return res.status(404).json({ message: 'Project not found' });
|
|
294
|
-
if (!(0, auth_1.
|
|
300
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
295
301
|
return res.status(403).json({ message: 'Unauthorized access' });
|
|
296
302
|
const connAdapter = await resolveConnAdapter(connId, project, auth);
|
|
297
303
|
if ('error' in connAdapter)
|
|
@@ -419,7 +425,7 @@ function storageRouter(config) {
|
|
|
419
425
|
const project = await Project.findOne({ _id: projectId });
|
|
420
426
|
if (!project)
|
|
421
427
|
return res.status(404).json({ message: 'Project not found' });
|
|
422
|
-
if (!(0, auth_1.
|
|
428
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
423
429
|
return res.status(403).json({ message: 'Unauthorized access' });
|
|
424
430
|
const collection = getRawFilesCollection();
|
|
425
431
|
if (!collection)
|
|
@@ -440,7 +446,7 @@ function storageRouter(config) {
|
|
|
440
446
|
const project = await Project.findOne({ _id: projectId });
|
|
441
447
|
if (!project)
|
|
442
448
|
return res.status(404).json({ message: 'Project not found' });
|
|
443
|
-
if (!(0, auth_1.
|
|
449
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
444
450
|
return res.status(403).json({ message: 'Unauthorized access' });
|
|
445
451
|
const connAdapter = await resolveConnAdapter(connId, project, auth);
|
|
446
452
|
if ('error' in connAdapter)
|
|
@@ -539,7 +545,7 @@ function storageRouter(config) {
|
|
|
539
545
|
const project = await Project.findOne({ _id: projectId });
|
|
540
546
|
if (!project)
|
|
541
547
|
return res.status(404).json({ message: 'Project not found' });
|
|
542
|
-
if (!(0, auth_1.
|
|
548
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
543
549
|
return res.status(403).json({ message: 'Unauthorized access' });
|
|
544
550
|
const conn = findStorageConn(project, connId);
|
|
545
551
|
const isBuiltin = conn?.source === 'builtin';
|
|
@@ -590,7 +596,7 @@ function storageRouter(config) {
|
|
|
590
596
|
const project = await Project.findOne({ _id: projectId });
|
|
591
597
|
if (!project)
|
|
592
598
|
return res.status(404).json({ message: 'Project not found' });
|
|
593
|
-
if (!(0, auth_1.
|
|
599
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
594
600
|
return res.status(403).json({ message: 'Unauthorized access' });
|
|
595
601
|
const collection = getRawFoldersCollection();
|
|
596
602
|
if (!collection)
|
|
@@ -624,7 +630,7 @@ function storageRouter(config) {
|
|
|
624
630
|
const project = await Project.findOne({ _id: projectId });
|
|
625
631
|
if (!project)
|
|
626
632
|
return res.status(404).json({ message: 'Project not found' });
|
|
627
|
-
if (!(0, auth_1.
|
|
633
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
628
634
|
return res.status(403).json({ message: 'Unauthorized access' });
|
|
629
635
|
const collection = getRawFoldersCollection();
|
|
630
636
|
if (!collection)
|
|
@@ -654,7 +660,7 @@ function storageRouter(config) {
|
|
|
654
660
|
const project = await Project.findOne({ _id: projectId });
|
|
655
661
|
if (!project)
|
|
656
662
|
return res.status(404).json({ message: 'Project not found' });
|
|
657
|
-
if (!(0, auth_1.
|
|
663
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
658
664
|
return res.status(403).json({ message: 'Unauthorized access' });
|
|
659
665
|
const foldersCollection = getRawFoldersCollection();
|
|
660
666
|
if (!foldersCollection)
|
|
@@ -682,7 +688,7 @@ function storageRouter(config) {
|
|
|
682
688
|
const project = await Project.findOne({ _id: projectId });
|
|
683
689
|
if (!project)
|
|
684
690
|
return res.status(404).json({ message: 'Project not found' });
|
|
685
|
-
if (!(0, auth_1.
|
|
691
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
686
692
|
return res.status(403).json({ message: 'Unauthorized access' });
|
|
687
693
|
if (folderId != null) {
|
|
688
694
|
const foldersCollection = getRawFoldersCollection();
|