@friggframework/core 2.0.0--canary.461.41b7566.0 → 2.0.0--canary.461.4066059.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.
|
@@ -118,9 +118,16 @@ async function checkDatabaseState(dbType) {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
const schemaPath = getPrismaSchemaPath(dbType);
|
|
121
|
+
const prismaBin = getPrismaBinaryPath();
|
|
122
|
+
|
|
123
|
+
// Use direct path instead of npx to avoid WASM file resolution issues
|
|
124
|
+
const isDirectBinary = prismaBin !== 'npx prisma';
|
|
125
|
+
const command = isDirectBinary
|
|
126
|
+
? `${prismaBin} migrate status --schema=${schemaPath}`
|
|
127
|
+
: `npx prisma migrate status --schema=${schemaPath}`;
|
|
121
128
|
|
|
122
129
|
const output = execSync(
|
|
123
|
-
|
|
130
|
+
command,
|
|
124
131
|
{
|
|
125
132
|
encoding: 'utf8',
|
|
126
133
|
stdio: 'pipe',
|
|
@@ -63,8 +63,8 @@ const {
|
|
|
63
63
|
GetUserFromAdopterJwt,
|
|
64
64
|
} = require('../user/use-cases/get-user-from-adopter-jwt');
|
|
65
65
|
const {
|
|
66
|
-
|
|
67
|
-
} = require('../user/use-cases/
|
|
66
|
+
AuthenticateWithSharedSecret,
|
|
67
|
+
} = require('../user/use-cases/authenticate-with-shared-secret');
|
|
68
68
|
const {
|
|
69
69
|
AuthenticateUser,
|
|
70
70
|
} = require('../user/use-cases/authenticate-user');
|
|
@@ -95,16 +95,13 @@ function createIntegrationRouter() {
|
|
|
95
95
|
userConfig,
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
const
|
|
99
|
-
userRepository,
|
|
100
|
-
userConfig,
|
|
101
|
-
});
|
|
98
|
+
const authenticateWithSharedSecret = new AuthenticateWithSharedSecret();
|
|
102
99
|
|
|
103
100
|
const authenticateUser = new AuthenticateUser({
|
|
104
101
|
getUserFromBearerToken,
|
|
105
102
|
getUserFromXFriggHeaders,
|
|
106
103
|
getUserFromAdopterJwt,
|
|
107
|
-
|
|
104
|
+
authenticateWithSharedSecret,
|
|
108
105
|
userConfig,
|
|
109
106
|
});
|
|
110
107
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/core",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.461.
|
|
4
|
+
"version": "2.0.0--canary.461.4066059.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-apigatewaymanagementapi": "^3.588.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.588.0",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@friggframework/eslint-config": "2.0.0--canary.461.
|
|
42
|
-
"@friggframework/prettier-config": "2.0.0--canary.461.
|
|
43
|
-
"@friggframework/test": "2.0.0--canary.461.
|
|
41
|
+
"@friggframework/eslint-config": "2.0.0--canary.461.4066059.0",
|
|
42
|
+
"@friggframework/prettier-config": "2.0.0--canary.461.4066059.0",
|
|
43
|
+
"@friggframework/test": "2.0.0--canary.461.4066059.0",
|
|
44
44
|
"@prisma/client": "^6.17.0",
|
|
45
45
|
"@types/lodash": "4.17.15",
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"publishConfig": {
|
|
81
81
|
"access": "public"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "4066059afecf11231ca7ff94cc4483b47f5b6e74"
|
|
84
84
|
}
|
|
@@ -21,20 +21,20 @@ class AuthenticateUser {
|
|
|
21
21
|
* @param {import('./get-user-from-bearer-token').GetUserFromBearerToken} params.getUserFromBearerToken - Use case for bearer token auth.
|
|
22
22
|
* @param {import('./get-user-from-x-frigg-headers').GetUserFromXFriggHeaders} params.getUserFromXFriggHeaders - Use case for x-frigg header auth.
|
|
23
23
|
* @param {import('./get-user-from-adopter-jwt').GetUserFromAdopterJwt} params.getUserFromAdopterJwt - Use case for adopter JWT auth.
|
|
24
|
-
* @param {import('./
|
|
24
|
+
* @param {import('./authenticate-with-shared-secret').AuthenticateWithSharedSecret} params.authenticateWithSharedSecret - Use case for validating shared secret.
|
|
25
25
|
* @param {Object} params.userConfig - The user config in the app definition.
|
|
26
26
|
*/
|
|
27
27
|
constructor({
|
|
28
28
|
getUserFromBearerToken,
|
|
29
29
|
getUserFromXFriggHeaders,
|
|
30
30
|
getUserFromAdopterJwt,
|
|
31
|
-
|
|
31
|
+
authenticateWithSharedSecret,
|
|
32
32
|
userConfig,
|
|
33
33
|
}) {
|
|
34
34
|
this.getUserFromBearerToken = getUserFromBearerToken;
|
|
35
35
|
this.getUserFromXFriggHeaders = getUserFromXFriggHeaders;
|
|
36
36
|
this.getUserFromAdopterJwt = getUserFromAdopterJwt;
|
|
37
|
-
this.
|
|
37
|
+
this.authenticateWithSharedSecret = authenticateWithSharedSecret;
|
|
38
38
|
this.userConfig = userConfig;
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -56,8 +56,10 @@ class AuthenticateUser {
|
|
|
56
56
|
if (authModes.sharedSecret !== false) {
|
|
57
57
|
const apiKey = req.headers['x-frigg-api-key'];
|
|
58
58
|
if (apiKey) {
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
// Validate the API key (authentication)
|
|
60
|
+
await this.authenticateWithSharedSecret.execute(apiKey);
|
|
61
|
+
// Get user from x-frigg headers (authorization)
|
|
62
|
+
return await this.getUserFromXFriggHeaders.execute(
|
|
61
63
|
appUserId,
|
|
62
64
|
appOrgId
|
|
63
65
|
);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const Boom = require('@hapi/boom');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Use case for authenticating requests with shared secret API key.
|
|
5
|
+
* This use case ONLY validates the authenticity of the request via API key.
|
|
6
|
+
* It does NOT retrieve user data - that's handled by GetUserFromXFriggHeaders.
|
|
7
|
+
*
|
|
8
|
+
* Used for backend-to-backend communication where the secret proves
|
|
9
|
+
* the request is legitimate, but user identification comes from x-frigg headers.
|
|
10
|
+
*
|
|
11
|
+
* @class AuthenticateWithSharedSecret
|
|
12
|
+
*/
|
|
13
|
+
class AuthenticateWithSharedSecret {
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new AuthenticateWithSharedSecret instance.
|
|
16
|
+
* @param {Object} params - Configuration parameters (none needed currently, but kept for consistency).
|
|
17
|
+
*/
|
|
18
|
+
constructor() {
|
|
19
|
+
// No dependencies needed - just validates against env var
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Validates the provided shared secret against FRIGG_API_KEY.
|
|
24
|
+
* @async
|
|
25
|
+
* @param {string} providedSecret - Secret from x-frigg-api-key header
|
|
26
|
+
* @returns {Promise<boolean>} True if valid (or throws error if invalid)
|
|
27
|
+
* @throws {Boom} 500 if FRIGG_API_KEY not configured
|
|
28
|
+
* @throws {Boom} 401 if provided secret doesn't match
|
|
29
|
+
*/
|
|
30
|
+
async execute(providedSecret) {
|
|
31
|
+
// Validate secret
|
|
32
|
+
const expectedSecret = process.env.FRIGG_API_KEY;
|
|
33
|
+
if (!expectedSecret) {
|
|
34
|
+
throw Boom.badImplementation(
|
|
35
|
+
'FRIGG_API_KEY environment variable is not configured. ' +
|
|
36
|
+
'Set FRIGG_API_KEY to enable shared secret authentication.'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!providedSecret || providedSecret !== expectedSecret) {
|
|
41
|
+
throw Boom.unauthorized('Invalid API key');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = { AuthenticateWithSharedSecret };
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
const Boom = require('@hapi/boom');
|
|
2
|
-
const { User } = require('../user');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Use case for authenticating requests with shared secret API key.
|
|
6
|
-
* Used for backend-to-backend communication where the secret proves
|
|
7
|
-
* authenticity, and x-frigg headers identify the user/org.
|
|
8
|
-
*
|
|
9
|
-
* This separates authentication (proving legitimacy via API key) from
|
|
10
|
-
* authorization (identifying user/org via x-frigg headers).
|
|
11
|
-
*
|
|
12
|
-
* @class GetUserFromSharedSecret
|
|
13
|
-
*/
|
|
14
|
-
class GetUserFromSharedSecret {
|
|
15
|
-
/**
|
|
16
|
-
* Creates a new GetUserFromSharedSecret instance.
|
|
17
|
-
* @param {Object} params - Configuration parameters.
|
|
18
|
-
* @param {import('../repositories/user-repository-interface').UserRepositoryInterface} params.userRepository - Repository for user data operations.
|
|
19
|
-
* @param {Object} params.userConfig - The user config in the app definition.
|
|
20
|
-
*/
|
|
21
|
-
constructor({ userRepository, userConfig }) {
|
|
22
|
-
this.userRepository = userRepository;
|
|
23
|
-
this.userConfig = userConfig;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Validates shared secret and extracts user from x-frigg headers.
|
|
28
|
-
* @async
|
|
29
|
-
* @param {string} providedSecret - Secret from x-frigg-api-key header
|
|
30
|
-
* @param {string} [appUserId] - From x-frigg-appuserid header
|
|
31
|
-
* @param {string} [appOrgId] - From x-frigg-apporgid header
|
|
32
|
-
* @returns {Promise<import('../user').User>} The authenticated user object.
|
|
33
|
-
* @throws {Boom} 500 if FRIGG_API_KEY not configured
|
|
34
|
-
* @throws {Boom} 401 if provided secret doesn't match
|
|
35
|
-
* @throws {Boom} 400 if no user identifiers provided or if they refer to different users
|
|
36
|
-
*/
|
|
37
|
-
async execute(providedSecret, appUserId, appOrgId) {
|
|
38
|
-
// Validate secret
|
|
39
|
-
const expectedSecret = process.env.FRIGG_API_KEY;
|
|
40
|
-
if (!expectedSecret) {
|
|
41
|
-
throw Boom.badImplementation(
|
|
42
|
-
'FRIGG_API_KEY environment variable is not configured. ' +
|
|
43
|
-
'Set FRIGG_API_KEY to enable shared secret authentication.'
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (!providedSecret || providedSecret !== expectedSecret) {
|
|
48
|
-
throw Boom.unauthorized('Invalid API key');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Require at least one user identifier
|
|
52
|
-
if (!appUserId && !appOrgId) {
|
|
53
|
-
throw Boom.badRequest(
|
|
54
|
-
'At least one of x-frigg-appuserid or x-frigg-apporgid headers is required with shared secret authentication'
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Find or create users (reuse logic from GetUserFromXFriggHeaders)
|
|
59
|
-
let individualUserData = null;
|
|
60
|
-
let organizationUserData = null;
|
|
61
|
-
|
|
62
|
-
if (appUserId && this.userConfig.individualUserRequired !== false) {
|
|
63
|
-
individualUserData =
|
|
64
|
-
await this.userRepository.findIndividualUserByAppUserId(
|
|
65
|
-
appUserId
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (appOrgId && this.userConfig.organizationUserRequired) {
|
|
70
|
-
organizationUserData =
|
|
71
|
-
await this.userRepository.findOrganizationUserByAppOrgId(
|
|
72
|
-
appOrgId
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// VALIDATION: If both IDs provided and both users exist, verify they match
|
|
77
|
-
if (
|
|
78
|
-
appUserId &&
|
|
79
|
-
appOrgId &&
|
|
80
|
-
individualUserData &&
|
|
81
|
-
organizationUserData
|
|
82
|
-
) {
|
|
83
|
-
const individualOrgId =
|
|
84
|
-
individualUserData.organizationUser?.toString();
|
|
85
|
-
const expectedOrgId = organizationUserData.id?.toString();
|
|
86
|
-
|
|
87
|
-
if (individualOrgId !== expectedOrgId) {
|
|
88
|
-
throw Boom.badRequest(
|
|
89
|
-
'User ID mismatch: x-frigg-appuserid and x-frigg-apporgid refer to different users. ' +
|
|
90
|
-
'Provide only one identifier or ensure they belong to the same user.'
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Auto-create user if not found
|
|
96
|
-
if (!individualUserData && !organizationUserData) {
|
|
97
|
-
if (appUserId) {
|
|
98
|
-
individualUserData =
|
|
99
|
-
await this.userRepository.createIndividualUser({
|
|
100
|
-
appUserId,
|
|
101
|
-
username: `api-user-${appUserId}`,
|
|
102
|
-
email: `${appUserId}@api.local`,
|
|
103
|
-
});
|
|
104
|
-
} else {
|
|
105
|
-
organizationUserData =
|
|
106
|
-
await this.userRepository.createOrganizationUser({
|
|
107
|
-
appOrgId,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return new User(
|
|
113
|
-
individualUserData,
|
|
114
|
-
organizationUserData,
|
|
115
|
-
this.userConfig.usePassword,
|
|
116
|
-
this.userConfig.primary,
|
|
117
|
-
this.userConfig.individualUserRequired,
|
|
118
|
-
this.userConfig.organizationUserRequired
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
module.exports = { GetUserFromSharedSecret };
|
|
124
|
-
|