|
|
@ -3,6 +3,7 @@ import { getAccessIdOfBearerToken } from '@ghostfolio/api/helper/bearer-token.he |
|
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; |
|
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; |
|
|
import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; |
|
|
import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; |
|
|
import { HEADER_KEY_TOKEN, MCP_REALM } from '@ghostfolio/common/config'; |
|
|
import { HEADER_KEY_TOKEN, MCP_REALM } from '@ghostfolio/common/config'; |
|
|
|
|
|
import { hasRole } from '@ghostfolio/common/permissions'; |
|
|
import type { ImpersonationContext } from '@ghostfolio/common/types'; |
|
|
import type { ImpersonationContext } from '@ghostfolio/common/types'; |
|
|
|
|
|
|
|
|
import { RequestClient } from '@prisma/client'; |
|
|
import { RequestClient } from '@prisma/client'; |
|
|
@ -20,6 +21,10 @@ import { getReasonPhrase, StatusCodes } from 'http-status-codes'; |
|
|
* authorization server. A client which reads the challenge asks the user for |
|
|
* authorization server. A client which reads the challenge asks the user for |
|
|
* the identifier of the access instead of starting a flow which would fail. |
|
|
* the identifier of the access instead of starting a flow which would fail. |
|
|
* |
|
|
* |
|
|
|
|
|
* With the subscription, the user who granted the access has the same limits |
|
|
|
|
|
* as with the other clients: an inactive user and a user who exceeds the daily |
|
|
|
|
|
* request limit get the status 429, which also has to come from here. |
|
|
|
|
|
* |
|
|
* An authorized request is counted in the analytics of the user who granted |
|
|
* An authorized request is counted in the analytics of the user who granted |
|
|
* the access, as the strategies do for the requests of the other clients. |
|
|
* the access, as the strategies do for the requests of the other clients. |
|
|
*/ |
|
|
*/ |
|
|
@ -65,6 +70,22 @@ export function createMcpAuthorizationMiddleware({ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { |
|
|
if (configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { |
|
|
|
|
|
const user = await userService.user({ id: impersonation.userId }); |
|
|
|
|
|
|
|
|
|
|
|
// The daily requests of an inactive user are not counted, as in the
|
|
|
|
|
|
// strategies
|
|
|
|
|
|
const isRequestLimitExceeded = |
|
|
|
|
|
hasRole(user, 'INACTIVE') || |
|
|
|
|
|
(await userService.isDailyRequestLimitExceeded({ user })); |
|
|
|
|
|
|
|
|
|
|
|
if (isRequestLimitExceeded) { |
|
|
|
|
|
return response.status(StatusCodes.TOO_MANY_REQUESTS).json({ |
|
|
|
|
|
error: getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), |
|
|
|
|
|
message: |
|
|
|
|
|
'The request limit of the user who granted the access is exceeded' |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
await userService.updateAnalytics({ |
|
|
await userService.updateAnalytics({ |
|
|
requestClient: RequestClient.MCP, |
|
|
requestClient: RequestClient.MCP, |
|
|
userId: impersonation.userId |
|
|
userId: impersonation.userId |
|
|
|