streamby-core 0.29.11 → 0.31.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/README.md +283 -283
- package/dist/adapters/database/connectionManager.js +78 -80
- package/dist/adapters/database/sql.js +1 -1
- package/dist/middleware/createRouter.js +0 -2
- package/dist/middleware/routes/ai.js +1 -1
- package/dist/middleware/routes/connection.js +35 -50
- package/dist/middleware/routes/dbConnection.js +17 -15
- package/dist/middleware/routes/distribution.js +5 -4
- package/dist/middleware/routes/export.js +10 -17
- package/dist/middleware/routes/project.js +1 -1
- package/dist/middleware/routes/renderFarm.js +5 -4
- package/dist/middleware/routes/storage.js +7 -5
- package/dist/middleware/routes/storageConnection.js +15 -12
- package/dist/models/Model.js +9 -9
- package/dist/services/backfillBuiltinConnections.js +0 -2
- package/dist/services/connection.d.ts +18 -0
- package/dist/services/connection.js +78 -0
- package/dist/services/executor.js +9 -12
- package/dist/services/projectIntegration.js +4 -4
- package/dist/types/index.d.ts +10 -16
- package/dist/utils/crypto.d.ts +3 -0
- package/dist/utils/crypto.js +32 -0
- package/dist/utils/sanitize.d.ts +10 -0
- package/dist/utils/sanitize.js +16 -1
- package/package.json +63 -63
|
@@ -9,6 +9,7 @@ const manager_1 = require("../../models/manager");
|
|
|
9
9
|
const auth_1 = require("../../utils/auth");
|
|
10
10
|
const jobQueue_1 = require("../../services/jobQueue");
|
|
11
11
|
const vfxProcessor_1 = require("../../services/vfxProcessor");
|
|
12
|
+
const sanitize_1 = require("../../utils/sanitize");
|
|
12
13
|
const crypto_1 = __importDefault(require("crypto"));
|
|
13
14
|
function renderFarmRouter(_config) {
|
|
14
15
|
const router = (0, express_1.Router)();
|
|
@@ -23,7 +24,7 @@ function renderFarmRouter(_config) {
|
|
|
23
24
|
return res.status(404).json({ message: 'Project not found' });
|
|
24
25
|
if (!(0, auth_1.isProjectMember)(project, auth.userId))
|
|
25
26
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
26
|
-
res.json({ connections: project.renderFarmConnections
|
|
27
|
+
res.json({ connections: (0, sanitize_1.sanitizeConnections)(project.renderFarmConnections) });
|
|
27
28
|
}
|
|
28
29
|
catch (err) {
|
|
29
30
|
res.status(500).json({ message: err.message });
|
|
@@ -33,7 +34,7 @@ function renderFarmRouter(_config) {
|
|
|
33
34
|
try {
|
|
34
35
|
const auth = req.auth;
|
|
35
36
|
const { projectId } = req.params;
|
|
36
|
-
const { name, provider, apiUrl,
|
|
37
|
+
const { name, provider, apiUrl, encryptedCredential, description } = req.body;
|
|
37
38
|
if (!name || !provider || !apiUrl) {
|
|
38
39
|
return res.status(400).json({ message: 'name, provider and apiUrl are required' });
|
|
39
40
|
}
|
|
@@ -47,13 +48,13 @@ function renderFarmRouter(_config) {
|
|
|
47
48
|
name,
|
|
48
49
|
provider,
|
|
49
50
|
apiUrl,
|
|
50
|
-
|
|
51
|
+
encryptedCredential,
|
|
51
52
|
description,
|
|
52
53
|
projectId,
|
|
53
54
|
createdAt: new Date(),
|
|
54
55
|
};
|
|
55
56
|
await Project.update({ _id: projectId }, { $push: { renderFarmConnections: connection } });
|
|
56
|
-
res.status(201).json({ connection });
|
|
57
|
+
res.status(201).json({ connection: (0, sanitize_1.sanitizeConnection)(connection) });
|
|
57
58
|
}
|
|
58
59
|
catch (err) {
|
|
59
60
|
res.status(500).json({ message: err.message });
|
|
@@ -61,8 +61,11 @@ function storageRouter(config) {
|
|
|
61
61
|
function connFilter(projectId, connId, project, extra) {
|
|
62
62
|
const conn = findStorageConn(project, connId);
|
|
63
63
|
const isBuiltin = conn?.source === 'builtin';
|
|
64
|
+
// Builtin files may be stamped one of two ways depending on when they were uploaded:
|
|
65
|
+
// legacy docs (pre-per-row-ids) used the builtin's config id (e.g. 'builtin') or have no
|
|
66
|
+
// storageConnectionId at all; current uploads use the row's own generated id (connId).
|
|
64
67
|
const connMatch = isBuiltin
|
|
65
|
-
? { $or: [{ storageConnectionId: connId }, { storageConnectionId: { $exists: false } }] }
|
|
68
|
+
? { $or: [{ storageConnectionId: connId }, { storageConnectionId: conn.integrationId }, { storageConnectionId: { $exists: false } }] }
|
|
66
69
|
: { storageConnectionId: connId };
|
|
67
70
|
return { projectId, ...connMatch, ...(extra ?? {}) };
|
|
68
71
|
}
|
|
@@ -95,11 +98,10 @@ function storageRouter(config) {
|
|
|
95
98
|
}
|
|
96
99
|
if (!(0, encryption_1.isEncryptionKeySet)())
|
|
97
100
|
return { error: 'Encryption key not set', status: 500 };
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return { error: 'Credential not found in project', status: 400 };
|
|
101
|
+
if (!conn.encryptedCredential)
|
|
102
|
+
return { error: 'Connection has no stored credential', status: 400 };
|
|
101
103
|
try {
|
|
102
|
-
const s3Config = JSON.parse((0, encryption_1.decrypt)(
|
|
104
|
+
const s3Config = JSON.parse((0, encryption_1.decrypt)(conn.encryptedCredential));
|
|
103
105
|
return new s3_1.S3Adapter(s3Config);
|
|
104
106
|
}
|
|
105
107
|
catch (e) {
|
|
@@ -6,6 +6,8 @@ const mongodb_1 = require("mongodb");
|
|
|
6
6
|
const manager_1 = require("../../models/manager");
|
|
7
7
|
const auth_1 = require("../../utils/auth");
|
|
8
8
|
const builtinAccess_1 = require("../../utils/builtinAccess");
|
|
9
|
+
const sanitize_1 = require("../../utils/sanitize");
|
|
10
|
+
const encryption_1 = require("../../utils/encryption");
|
|
9
11
|
const VALID_STORAGE_TYPES = ['s3', 'gcs', 'r2', 'azure'];
|
|
10
12
|
function storageConnectionRouter(config) {
|
|
11
13
|
const router = (0, express_1.Router)();
|
|
@@ -24,9 +26,9 @@ function storageConnectionRouter(config) {
|
|
|
24
26
|
// "validate on every use" (TCORE-69). BYOC (source: 'integration') is always available.
|
|
25
27
|
const data = await Promise.all(connections.map(async (conn) => {
|
|
26
28
|
if (conn.source !== 'builtin')
|
|
27
|
-
return conn;
|
|
29
|
+
return (0, sanitize_1.sanitizeConnection)(conn);
|
|
28
30
|
const available = await (0, builtinAccess_1.assertBuiltinAccess)(auth, conn.integrationId ?? conn.id, config, 'storage');
|
|
29
|
-
return { ...conn, isBuiltin: true, available };
|
|
31
|
+
return (0, sanitize_1.sanitizeConnection)({ ...conn, isBuiltin: true, available });
|
|
30
32
|
}));
|
|
31
33
|
return res.status(200).json({ data });
|
|
32
34
|
}
|
|
@@ -41,15 +43,15 @@ function storageConnectionRouter(config) {
|
|
|
41
43
|
if (auth.role !== 'admin' && auth.role !== 'editor') {
|
|
42
44
|
return res.status(403).json({ message: 'Permission denied' });
|
|
43
45
|
}
|
|
44
|
-
const { name, type,
|
|
46
|
+
const { name, type, credential, integrationId, description } = req.body;
|
|
45
47
|
if (!name || !type) {
|
|
46
48
|
return res.status(400).json({ message: 'name and type are required' });
|
|
47
49
|
}
|
|
48
|
-
if (!
|
|
49
|
-
return res.status(400).json({ message: 'Either
|
|
50
|
+
if (!credential && !integrationId) {
|
|
51
|
+
return res.status(400).json({ message: 'Either credential or integrationId is required' });
|
|
50
52
|
}
|
|
51
|
-
if (
|
|
52
|
-
return res.status(400).json({ message: 'Provide only one of
|
|
53
|
+
if (credential && integrationId) {
|
|
54
|
+
return res.status(400).json({ message: 'Provide only one of credential or integrationId' });
|
|
53
55
|
}
|
|
54
56
|
if (!VALID_STORAGE_TYPES.includes(type)) {
|
|
55
57
|
return res.status(400).json({ message: `type must be one of: ${VALID_STORAGE_TYPES.join(', ')}` });
|
|
@@ -59,6 +61,7 @@ function storageConnectionRouter(config) {
|
|
|
59
61
|
return res.status(404).json({ message: 'Project not found' });
|
|
60
62
|
if (!(0, auth_1.isProjectMember)(project, auth.userId))
|
|
61
63
|
return res.status(403).json({ message: 'Unauthorized project access' });
|
|
64
|
+
let encryptedCredential;
|
|
62
65
|
if (integrationId) {
|
|
63
66
|
const UserIntegrationModel = (0, manager_1.getModel)('user_integrations');
|
|
64
67
|
const integration = await UserIntegrationModel.findOne({ id: integrationId, userId: auth.userId });
|
|
@@ -68,23 +71,23 @@ function storageConnectionRouter(config) {
|
|
|
68
71
|
return res.status(400).json({ message: 'Integration is not a storage integration' });
|
|
69
72
|
}
|
|
70
73
|
else {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
if (!(0, encryption_1.isEncryptionKeySet)())
|
|
75
|
+
return res.status(500).json({ message: 'Encryption key is not set' });
|
|
76
|
+
encryptedCredential = (0, encryption_1.encrypt)(credential);
|
|
74
77
|
}
|
|
75
78
|
const connection = {
|
|
76
79
|
id: new mongodb_1.ObjectId().toHexString(),
|
|
77
80
|
name,
|
|
78
81
|
type,
|
|
79
|
-
credentialId: credentialId ?? '',
|
|
80
82
|
projectId: req.params.id,
|
|
81
83
|
createdAt: new Date(),
|
|
82
84
|
source: integrationId ? 'integration' : 'manual',
|
|
83
85
|
...(integrationId && { integrationId }),
|
|
86
|
+
...(encryptedCredential !== undefined && { encryptedCredential }),
|
|
84
87
|
...(description !== undefined && { description }),
|
|
85
88
|
};
|
|
86
89
|
await Project.update({ _id: req.params.id }, { $push: { storageConnections: connection } });
|
|
87
|
-
return res.status(201).json({ data: connection });
|
|
90
|
+
return res.status(201).json({ data: (0, sanitize_1.sanitizeConnection)(connection) });
|
|
88
91
|
}
|
|
89
92
|
catch (err) {
|
|
90
93
|
res.status(500).json({ message: 'Failed to add storage connection', details: err.message });
|
package/dist/models/Model.js
CHANGED
|
@@ -45,11 +45,11 @@ class Model {
|
|
|
45
45
|
// Handle members filter for SQL projects
|
|
46
46
|
const userId = processedFilter.members.$elemMatch.userId;
|
|
47
47
|
const schema = this.schema || 'streamby'; // Default to 'streamby' if schema not provided
|
|
48
|
-
const query = `
|
|
49
|
-
SELECT p.*, pm."userId" as memberUserId, pm.role as memberRole, pm.status as memberStatus, pm.archived as memberArchived
|
|
50
|
-
FROM "${schema}"."projects" p
|
|
51
|
-
JOIN "${schema}"."project_members" pm ON p.id = pm."projectId"
|
|
52
|
-
WHERE pm."userId" = $1
|
|
48
|
+
const query = `
|
|
49
|
+
SELECT p.*, pm."userId" as memberUserId, pm.role as memberRole, pm.status as memberStatus, pm.archived as memberArchived
|
|
50
|
+
FROM "${schema}"."projects" p
|
|
51
|
+
JOIN "${schema}"."project_members" pm ON p.id = pm."projectId"
|
|
52
|
+
WHERE pm."userId" = $1
|
|
53
53
|
`;
|
|
54
54
|
const result = await connection.query(query, [userId]);
|
|
55
55
|
sqlResults = result.rows.map(row => ({
|
|
@@ -219,10 +219,10 @@ class Model {
|
|
|
219
219
|
else {
|
|
220
220
|
const matchKey = value.id !== undefined ? 'id' : Object.keys(value)[0];
|
|
221
221
|
const matchVal = String(value[matchKey]);
|
|
222
|
-
await connection.query(`UPDATE ${tbl} SET "${field}" = (
|
|
223
|
-
SELECT COALESCE(jsonb_agg(elem), '[]'::jsonb)
|
|
224
|
-
FROM jsonb_array_elements("${field}") elem
|
|
225
|
-
WHERE elem->>'${matchKey}' != $1
|
|
222
|
+
await connection.query(`UPDATE ${tbl} SET "${field}" = (
|
|
223
|
+
SELECT COALESCE(jsonb_agg(elem), '[]'::jsonb)
|
|
224
|
+
FROM jsonb_array_elements("${field}") elem
|
|
225
|
+
WHERE elem->>'${matchKey}' != $1
|
|
226
226
|
) WHERE id = $2`, [matchVal, id]);
|
|
227
227
|
}
|
|
228
228
|
}
|
|
@@ -29,7 +29,6 @@ async function backfillBuiltinConnections(config) {
|
|
|
29
29
|
id: crypto_1.default.randomUUID(),
|
|
30
30
|
name: builtinAccess_1.BUILTIN_DB_DISPLAY[db.type] ?? db.type,
|
|
31
31
|
dbType: db.type === 'sql' ? 'postgresql' : 'mongodb',
|
|
32
|
-
credentialId: '',
|
|
33
32
|
projectId: project.id,
|
|
34
33
|
createdAt: now,
|
|
35
34
|
isBuiltin: true,
|
|
@@ -40,7 +39,6 @@ async function backfillBuiltinConnections(config) {
|
|
|
40
39
|
id: crypto_1.default.randomUUID(),
|
|
41
40
|
name: builtinAccess_1.BUILTIN_STORAGE_DISPLAY[provider.type] ?? provider.type,
|
|
42
41
|
type: provider.type,
|
|
43
|
-
credentialId: '',
|
|
44
42
|
projectId: project.id,
|
|
45
43
|
createdAt: now,
|
|
46
44
|
isBuiltin: true,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { StreamByConfig, Connection, ConnectionMethod } from '../types';
|
|
2
|
+
export declare function addConnection(config: StreamByConfig, projectId: string, data: {
|
|
3
|
+
name: string;
|
|
4
|
+
apiUrl: string;
|
|
5
|
+
method: ConnectionMethod;
|
|
6
|
+
prefix?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
token?: string;
|
|
9
|
+
}): Promise<Connection>;
|
|
10
|
+
export declare function updateConnection(config: StreamByConfig, projectId: string, connectionId: string, data: {
|
|
11
|
+
name?: string;
|
|
12
|
+
apiUrl?: string;
|
|
13
|
+
method?: ConnectionMethod;
|
|
14
|
+
prefix?: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
token?: string;
|
|
17
|
+
}): Promise<Connection>;
|
|
18
|
+
export declare function deleteConnection(config: StreamByConfig, projectId: string, connectionId: string): Promise<void>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addConnection = addConnection;
|
|
4
|
+
exports.updateConnection = updateConnection;
|
|
5
|
+
exports.deleteConnection = deleteConnection;
|
|
6
|
+
const mongodb_1 = require("mongodb");
|
|
7
|
+
const manager_1 = require("../models/manager");
|
|
8
|
+
const encryption_1 = require("../utils/encryption");
|
|
9
|
+
async function addConnection(config, projectId, data) {
|
|
10
|
+
const ProjectModel = (0, manager_1.getModel)('projects');
|
|
11
|
+
const project = await ProjectModel.findOne({ _id: projectId });
|
|
12
|
+
if (!project) {
|
|
13
|
+
throw new Error('Project not found.');
|
|
14
|
+
}
|
|
15
|
+
let encryptedCredential;
|
|
16
|
+
if (data.token) {
|
|
17
|
+
if (!(0, encryption_1.isEncryptionKeySet)())
|
|
18
|
+
throw new Error('Encryption key is not set. Cannot encrypt credential.');
|
|
19
|
+
encryptedCredential = (0, encryption_1.encrypt)(data.token);
|
|
20
|
+
}
|
|
21
|
+
const connection = {
|
|
22
|
+
id: new mongodb_1.ObjectId().toHexString(),
|
|
23
|
+
name: data.name,
|
|
24
|
+
prefix: data.prefix,
|
|
25
|
+
apiUrl: data.apiUrl,
|
|
26
|
+
method: data.method,
|
|
27
|
+
projectId,
|
|
28
|
+
createdAt: new Date(),
|
|
29
|
+
...(data.description !== undefined && { description: data.description }),
|
|
30
|
+
...(encryptedCredential !== undefined && { encryptedCredential }),
|
|
31
|
+
};
|
|
32
|
+
const updatedProject = await ProjectModel.update({ _id: projectId }, { $push: { connections: connection } });
|
|
33
|
+
if (!updatedProject) {
|
|
34
|
+
throw new Error('Failed to add connection to project.');
|
|
35
|
+
}
|
|
36
|
+
return connection;
|
|
37
|
+
}
|
|
38
|
+
async function updateConnection(config, projectId, connectionId, data) {
|
|
39
|
+
const ProjectModel = (0, manager_1.getModel)('projects');
|
|
40
|
+
const project = await ProjectModel.findOne({ _id: projectId });
|
|
41
|
+
if (!project)
|
|
42
|
+
throw new Error('Project not found.');
|
|
43
|
+
const connections = project.connections ?? [];
|
|
44
|
+
const index = connections.findIndex((c) => c.id === connectionId);
|
|
45
|
+
if (index === -1)
|
|
46
|
+
throw new Error('Connection not found.');
|
|
47
|
+
let encryptedCredential;
|
|
48
|
+
if (data.token) {
|
|
49
|
+
if (!(0, encryption_1.isEncryptionKeySet)())
|
|
50
|
+
throw new Error('Encryption key is not set. Cannot encrypt credential.');
|
|
51
|
+
encryptedCredential = (0, encryption_1.encrypt)(data.token);
|
|
52
|
+
}
|
|
53
|
+
const updated = {
|
|
54
|
+
...connections[index],
|
|
55
|
+
...(data.name !== undefined && { name: data.name }),
|
|
56
|
+
...(data.apiUrl !== undefined && { apiUrl: data.apiUrl }),
|
|
57
|
+
...(data.method !== undefined && { method: data.method }),
|
|
58
|
+
...(data.prefix !== undefined && { prefix: data.prefix }),
|
|
59
|
+
...(data.description !== undefined && { description: data.description }),
|
|
60
|
+
...(encryptedCredential !== undefined && { encryptedCredential }),
|
|
61
|
+
};
|
|
62
|
+
connections[index] = updated;
|
|
63
|
+
const result = await ProjectModel.update({ _id: projectId }, { $set: { connections } });
|
|
64
|
+
if (!result)
|
|
65
|
+
throw new Error('Failed to update connection.');
|
|
66
|
+
return updated;
|
|
67
|
+
}
|
|
68
|
+
async function deleteConnection(config, projectId, connectionId) {
|
|
69
|
+
const ProjectModel = (0, manager_1.getModel)('projects');
|
|
70
|
+
const project = await ProjectModel.findOne({ _id: projectId });
|
|
71
|
+
if (!project) {
|
|
72
|
+
throw new Error('Project not found.');
|
|
73
|
+
}
|
|
74
|
+
const updatedProject = await ProjectModel.update({ _id: projectId }, { $pull: { connections: { id: connectionId } } });
|
|
75
|
+
if (!updatedProject) {
|
|
76
|
+
throw new Error('Failed to delete connection from project.');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -114,22 +114,19 @@ async function executeExport(nodeSchema, project, config) {
|
|
|
114
114
|
dataResults.push(await fetchData(client, type));
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
|
-
else if (node.type === '
|
|
118
|
-
const
|
|
119
|
-
if (!
|
|
117
|
+
else if (node.type === 'connectionNode') {
|
|
118
|
+
const connection = project.connections?.find((c) => c.id === node.data?.connectionId);
|
|
119
|
+
if (!connection)
|
|
120
120
|
continue;
|
|
121
121
|
const headers = { 'Content-Type': 'application/json' };
|
|
122
|
-
if (
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const prefix = apiConnection.prefix ? `${apiConnection.prefix} ` : '';
|
|
127
|
-
headers['Authorization'] = `${prefix}${decrypted}`;
|
|
128
|
-
}
|
|
122
|
+
if (connection.encryptedCredential && (0, encryption_1.isEncryptionKeySet)()) {
|
|
123
|
+
const decrypted = (0, encryption_1.decrypt)(connection.encryptedCredential);
|
|
124
|
+
const prefix = connection.prefix ? `${connection.prefix} ` : '';
|
|
125
|
+
headers['Authorization'] = `${prefix}${decrypted}`;
|
|
129
126
|
}
|
|
130
|
-
const response = await fetch(
|
|
127
|
+
const response = await fetch(connection.apiUrl, { method: connection.method || 'GET', headers });
|
|
131
128
|
if (!response.ok)
|
|
132
|
-
throw new Error(`
|
|
129
|
+
throw new Error(`Connection fetch failed: ${response.statusText}`);
|
|
133
130
|
dataResults.push(await response.json());
|
|
134
131
|
}
|
|
135
132
|
}
|
|
@@ -22,7 +22,7 @@ async function classifyIntegrationId(id, auth, config, projectId) {
|
|
|
22
22
|
kind: 'database',
|
|
23
23
|
connection: {
|
|
24
24
|
id: crypto_1.default.randomUUID(), name: builtinAccess_1.BUILTIN_DB_DISPLAY[db.type] ?? db.type, dbType: db.type === 'sql' ? 'postgresql' : 'mongodb',
|
|
25
|
-
|
|
25
|
+
projectId, createdAt: now, isBuiltin: true, integrationId: id, source: 'builtin',
|
|
26
26
|
},
|
|
27
27
|
};
|
|
28
28
|
}
|
|
@@ -35,7 +35,7 @@ async function classifyIntegrationId(id, auth, config, projectId) {
|
|
|
35
35
|
kind: 'storage',
|
|
36
36
|
connection: {
|
|
37
37
|
id: crypto_1.default.randomUUID(), name: builtinAccess_1.BUILTIN_STORAGE_DISPLAY[provider.type] ?? provider.type, type: provider.type,
|
|
38
|
-
|
|
38
|
+
projectId, createdAt: now, isBuiltin: true, integrationId: id, source: 'builtin',
|
|
39
39
|
},
|
|
40
40
|
};
|
|
41
41
|
}
|
|
@@ -49,7 +49,7 @@ async function classifyIntegrationId(id, auth, config, projectId) {
|
|
|
49
49
|
kind: 'database',
|
|
50
50
|
connection: {
|
|
51
51
|
id: crypto_1.default.randomUUID(), name: integration.name, dbType: integration.provider,
|
|
52
|
-
|
|
52
|
+
projectId, createdAt: now, isBuiltin: false, integrationId: id, source: 'integration',
|
|
53
53
|
},
|
|
54
54
|
};
|
|
55
55
|
}
|
|
@@ -57,7 +57,7 @@ async function classifyIntegrationId(id, auth, config, projectId) {
|
|
|
57
57
|
kind: 'storage',
|
|
58
58
|
connection: {
|
|
59
59
|
id: crypto_1.default.randomUUID(), name: integration.name, type: integration.provider,
|
|
60
|
-
|
|
60
|
+
projectId, createdAt: now, isBuiltin: false, integrationId: id, source: 'integration',
|
|
61
61
|
},
|
|
62
62
|
};
|
|
63
63
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export interface StorageConnection {
|
|
|
12
12
|
id: string;
|
|
13
13
|
name: string;
|
|
14
14
|
type: StorageConnectionType;
|
|
15
|
-
|
|
15
|
+
encryptedCredential?: string;
|
|
16
16
|
projectId: string;
|
|
17
17
|
createdAt: Date;
|
|
18
18
|
description?: string;
|
|
@@ -73,29 +73,23 @@ export interface ProjectInfo {
|
|
|
73
73
|
allowUpload?: boolean;
|
|
74
74
|
allowSharing?: boolean;
|
|
75
75
|
};
|
|
76
|
-
|
|
77
|
-
apiConnections?: ApiConnection[];
|
|
76
|
+
connections?: Connection[];
|
|
78
77
|
dbConnections?: DbConnection[];
|
|
79
78
|
storageConnections?: StorageConnection[];
|
|
80
79
|
pipelines?: PipelineRef[];
|
|
81
80
|
builtinBackfilledAt?: Date;
|
|
82
81
|
}
|
|
83
|
-
export
|
|
84
|
-
|
|
85
|
-
key: string;
|
|
86
|
-
encryptedValue: string;
|
|
87
|
-
}
|
|
88
|
-
export type ApiConnectionMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
|
89
|
-
export interface ApiConnection {
|
|
82
|
+
export type ConnectionMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
|
83
|
+
export interface Connection {
|
|
90
84
|
id: string;
|
|
91
85
|
name: string;
|
|
92
86
|
apiUrl: string;
|
|
93
|
-
method:
|
|
87
|
+
method: ConnectionMethod;
|
|
94
88
|
projectId: string;
|
|
95
89
|
createdAt: Date;
|
|
96
90
|
prefix?: string;
|
|
97
91
|
description?: string;
|
|
98
|
-
|
|
92
|
+
encryptedCredential?: string;
|
|
99
93
|
}
|
|
100
94
|
export interface ProjectListInfo {
|
|
101
95
|
id: string;
|
|
@@ -153,7 +147,7 @@ export interface DbConnection {
|
|
|
153
147
|
id: string;
|
|
154
148
|
name: string;
|
|
155
149
|
dbType: ExternalDbType;
|
|
156
|
-
|
|
150
|
+
encryptedCredential?: string;
|
|
157
151
|
projectId: string;
|
|
158
152
|
createdAt: Date;
|
|
159
153
|
description?: string;
|
|
@@ -214,7 +208,7 @@ export interface Export {
|
|
|
214
208
|
fields?: FieldDefinition[];
|
|
215
209
|
jsonData?: any;
|
|
216
210
|
apiUrl?: string;
|
|
217
|
-
|
|
211
|
+
encryptedCredential?: string;
|
|
218
212
|
prefix?: string;
|
|
219
213
|
private?: boolean;
|
|
220
214
|
allowedOrigin?: string[];
|
|
@@ -244,7 +238,7 @@ export interface DistributionConnection {
|
|
|
244
238
|
id: string;
|
|
245
239
|
name: string;
|
|
246
240
|
target: DistributionTarget;
|
|
247
|
-
|
|
241
|
+
encryptedCredential?: string;
|
|
248
242
|
projectId: string;
|
|
249
243
|
config: Record<string, string>;
|
|
250
244
|
createdAt: Date;
|
|
@@ -289,7 +283,7 @@ export interface RenderFarmConnection {
|
|
|
289
283
|
name: string;
|
|
290
284
|
provider: RenderFarmProvider;
|
|
291
285
|
apiUrl: string;
|
|
292
|
-
|
|
286
|
+
encryptedCredential?: string;
|
|
293
287
|
projectId: string;
|
|
294
288
|
createdAt: Date;
|
|
295
289
|
description?: string;
|
|
@@ -0,0 +1,32 @@
|
|
|
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.encrypt = encrypt;
|
|
7
|
+
exports.decrypt = decrypt;
|
|
8
|
+
exports.hash = hash;
|
|
9
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
+
const ALGORITHM = 'aes-256-cbc';
|
|
11
|
+
const IV_LENGTH = 16;
|
|
12
|
+
function encrypt(text, secretKey) {
|
|
13
|
+
const iv = crypto_1.default.randomBytes(IV_LENGTH);
|
|
14
|
+
const key = crypto_1.default.createHash('sha256').update(String(secretKey)).digest('base64').substr(0, 32);
|
|
15
|
+
const cipher = crypto_1.default.createCipheriv(ALGORITHM, Buffer.from(key), iv);
|
|
16
|
+
let encrypted = cipher.update(text);
|
|
17
|
+
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
|
18
|
+
return iv.toString('hex') + ':' + encrypted.toString('hex');
|
|
19
|
+
}
|
|
20
|
+
function decrypt(text, secretKey) {
|
|
21
|
+
const textParts = text.split(':');
|
|
22
|
+
const iv = Buffer.from(textParts.shift(), 'hex');
|
|
23
|
+
const encryptedText = Buffer.from(textParts.join(':'), 'hex');
|
|
24
|
+
const key = crypto_1.default.createHash('sha256').update(String(secretKey)).digest('base64').substr(0, 32);
|
|
25
|
+
const decipher = crypto_1.default.createDecipheriv(ALGORITHM, Buffer.from(key), iv);
|
|
26
|
+
let decrypted = decipher.update(encryptedText);
|
|
27
|
+
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
|
28
|
+
return decrypted.toString();
|
|
29
|
+
}
|
|
30
|
+
function hash(text) {
|
|
31
|
+
return crypto_1.default.createHash('sha256').update(text).digest('hex');
|
|
32
|
+
}
|
package/dist/utils/sanitize.d.ts
CHANGED
|
@@ -1,2 +1,12 @@
|
|
|
1
|
+
export declare function sanitizeConnection<T extends {
|
|
2
|
+
encryptedCredential?: string;
|
|
3
|
+
}>(conn: T): Omit<T, 'encryptedCredential'> & {
|
|
4
|
+
hasCredential: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function sanitizeConnections<T extends {
|
|
7
|
+
encryptedCredential?: string;
|
|
8
|
+
}>(conns: T[] | undefined): (Omit<T, 'encryptedCredential'> & {
|
|
9
|
+
hasCredential: boolean;
|
|
10
|
+
})[];
|
|
1
11
|
export declare function sanitizeProject(project: any): any;
|
|
2
12
|
export declare function sanitizeUserIntegration(integration: any): any;
|
package/dist/utils/sanitize.js
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanitizeConnection = sanitizeConnection;
|
|
4
|
+
exports.sanitizeConnections = sanitizeConnections;
|
|
3
5
|
exports.sanitizeProject = sanitizeProject;
|
|
4
6
|
exports.sanitizeUserIntegration = sanitizeUserIntegration;
|
|
7
|
+
function sanitizeConnection(conn) {
|
|
8
|
+
const { encryptedCredential, ...rest } = conn;
|
|
9
|
+
return { ...rest, hasCredential: !!encryptedCredential };
|
|
10
|
+
}
|
|
11
|
+
function sanitizeConnections(conns) {
|
|
12
|
+
return (conns ?? []).map(sanitizeConnection);
|
|
13
|
+
}
|
|
5
14
|
function sanitizeProject(project) {
|
|
6
15
|
if (!project)
|
|
7
16
|
return project;
|
|
8
17
|
return {
|
|
9
18
|
...project,
|
|
10
|
-
credentials:
|
|
19
|
+
credentials: undefined,
|
|
20
|
+
connections: sanitizeConnections(project.connections),
|
|
21
|
+
storageConnections: sanitizeConnections(project.storageConnections),
|
|
22
|
+
dbConnections: sanitizeConnections(project.dbConnections),
|
|
23
|
+
distributionConnections: sanitizeConnections(project.distributionConnections),
|
|
24
|
+
renderFarmConnections: sanitizeConnections(project.renderFarmConnections),
|
|
25
|
+
exports: project.exports?.map((e) => e && 'encryptedCredential' in e ? sanitizeConnection(e) : e),
|
|
11
26
|
};
|
|
12
27
|
}
|
|
13
28
|
function sanitizeUserIntegration(integration) {
|
package/package.json
CHANGED
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "streamby-core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "StreamBy middleware framework for media storage management",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
"dist"
|
|
9
|
-
],
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "tsc",
|
|
12
|
-
"test": "vitest",
|
|
13
|
-
"dev": "ts-node-dev --respawn --clear dev.ts",
|
|
14
|
-
"prepublishOnly": "npm run build"
|
|
15
|
-
},
|
|
16
|
-
"repository": {
|
|
17
|
-
"type": "git",
|
|
18
|
-
"url": "https://github.com/GwerhDev/StreamBy-Package.git"
|
|
19
|
-
},
|
|
20
|
-
"keywords": [
|
|
21
|
-
"streamby",
|
|
22
|
-
"middleware",
|
|
23
|
-
"upload",
|
|
24
|
-
"storage",
|
|
25
|
-
"s3",
|
|
26
|
-
"express",
|
|
27
|
-
"typescript"
|
|
28
|
-
],
|
|
29
|
-
"author": "TerminalCore Labs",
|
|
30
|
-
"license": "MIT",
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"@aws-sdk/client-s3": "^3.528.0",
|
|
33
|
-
"@aws-sdk/s3-request-presigner": "^3.787.0",
|
|
34
|
-
"@prisma/client": "^6.12.0",
|
|
35
|
-
"bcrypt": "^5.1.1",
|
|
36
|
-
"dotenv": "^16.5.0",
|
|
37
|
-
"express": "^4.0.0",
|
|
38
|
-
"mongodb": "^6.17.0",
|
|
39
|
-
"mongoose": "^8.13.2",
|
|
40
|
-
"node-fetch": "^3.0.0",
|
|
41
|
-
"pg": "^8.16.3",
|
|
42
|
-
"prisma": "^6.12.0",
|
|
43
|
-
"ws": "^8.20.0"
|
|
44
|
-
},
|
|
45
|
-
"devDependencies": {
|
|
46
|
-
"@types/bcrypt": "^5.0.2",
|
|
47
|
-
"@types/cors": "^2.8.18",
|
|
48
|
-
"@types/express": "^4.17.17",
|
|
49
|
-
"@types/mongodb": "^4.0.7",
|
|
50
|
-
"@types/node": "^22.15.21",
|
|
51
|
-
"@types/pg": "^8.15.4",
|
|
52
|
-
"@types/supertest": "^6.0.3",
|
|
53
|
-
"@types/ws": "^8.18.1",
|
|
54
|
-
"cors": "^2.8.5",
|
|
55
|
-
"supertest": "^7.1.4",
|
|
56
|
-
"ts-node-dev": "^2.0.0",
|
|
57
|
-
"typescript": "^5.8.3",
|
|
58
|
-
"vitest": "^3.1.1"
|
|
59
|
-
},
|
|
60
|
-
"peerDependencies": {
|
|
61
|
-
"express": "^4.0.0"
|
|
62
|
-
}
|
|
63
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "streamby-core",
|
|
3
|
+
"version": "0.31.0",
|
|
4
|
+
"description": "StreamBy middleware framework for media storage management",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"test": "vitest",
|
|
13
|
+
"dev": "ts-node-dev --respawn --clear dev.ts",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/GwerhDev/StreamBy-Package.git"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"streamby",
|
|
22
|
+
"middleware",
|
|
23
|
+
"upload",
|
|
24
|
+
"storage",
|
|
25
|
+
"s3",
|
|
26
|
+
"express",
|
|
27
|
+
"typescript"
|
|
28
|
+
],
|
|
29
|
+
"author": "TerminalCore Labs",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@aws-sdk/client-s3": "^3.528.0",
|
|
33
|
+
"@aws-sdk/s3-request-presigner": "^3.787.0",
|
|
34
|
+
"@prisma/client": "^6.12.0",
|
|
35
|
+
"bcrypt": "^5.1.1",
|
|
36
|
+
"dotenv": "^16.5.0",
|
|
37
|
+
"express": "^4.0.0",
|
|
38
|
+
"mongodb": "^6.17.0",
|
|
39
|
+
"mongoose": "^8.13.2",
|
|
40
|
+
"node-fetch": "^3.0.0",
|
|
41
|
+
"pg": "^8.16.3",
|
|
42
|
+
"prisma": "^6.12.0",
|
|
43
|
+
"ws": "^8.20.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/bcrypt": "^5.0.2",
|
|
47
|
+
"@types/cors": "^2.8.18",
|
|
48
|
+
"@types/express": "^4.17.17",
|
|
49
|
+
"@types/mongodb": "^4.0.7",
|
|
50
|
+
"@types/node": "^22.15.21",
|
|
51
|
+
"@types/pg": "^8.15.4",
|
|
52
|
+
"@types/supertest": "^6.0.3",
|
|
53
|
+
"@types/ws": "^8.18.1",
|
|
54
|
+
"cors": "^2.8.5",
|
|
55
|
+
"supertest": "^7.1.4",
|
|
56
|
+
"ts-node-dev": "^2.0.0",
|
|
57
|
+
"typescript": "^5.8.3",
|
|
58
|
+
"vitest": "^3.1.1"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"express": "^4.0.0"
|
|
62
|
+
}
|
|
63
|
+
}
|