diff --git a/.husky/pre-push b/.husky/pre-push index ee3c0acbf..ccf05aa56 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -28,9 +28,7 @@ while read local_ref local_sha remote_ref remote_sha; do echo "${CYAN}â„šī¸ Skipping merge commit $commit${RESET}" continue fi - - sig_status=$(git log --format='%G?' -n 1 $commit) - + sig_status=$(git log --format='%G?' -n 1 $commit) # Currently only check for "N" - for no signature. if [ "$sig_status" = "N" ]; then unsigned_commits="$unsigned_commits $commit" @@ -64,7 +62,6 @@ while read local_ref local_sha remote_ref remote_sha; do echo "${YELLOW}You can manually sign commits using:${RESET}" echo # Latest commit (HEAD) - head_commit=$(git rev-parse HEAD) echo " - For the latest commit (HEAD):" echo " git commit --amend -sS --no-edit" echo @@ -75,7 +72,6 @@ while read local_ref local_sha remote_ref remote_sha; do echo " - For the earliest unsigned commit $short_hash (skipping merge commits):" echo " git rebase --onto $parent_commit $parent_commit \\" echo " --exec 'if [ \$(git rev-list --parents -n 1 HEAD | awk \"{print NF-1}\") -eq 1 ]; then git commit --amend -sS --no-edit; else echo \"Skipping merge commit \$(git rev-parse --short HEAD)\"; fi'" - echo echo "Then push normally with:" echo " git push" @@ -92,4 +88,4 @@ while read local_ref local_sha remote_ref remote_sha; do fi done -echo "${GREEN}✅ All commits are signed and verified${RESET}" +echo "${GREEN}✅ No unsigned commits found${RESET}" \ No newline at end of file diff --git a/apps/api-gateway/src/organization/dtos/client-token.dto.ts b/apps/api-gateway/src/organization/dtos/client-token.dto.ts new file mode 100644 index 000000000..abd95d8e7 --- /dev/null +++ b/apps/api-gateway/src/organization/dtos/client-token.dto.ts @@ -0,0 +1,24 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsString } from 'class-validator'; + +export class ClientTokenDto { + @ApiProperty() + @IsString({ message: 'orgId must be in string format.' }) + orgId: string; + + @ApiProperty() + @IsString({ message: 'clientAlias must be in string format.' }) + clientAlias: string; + + @ApiProperty() + @IsString({ message: 'clientId must be in string format.' }) + clientId: string; + + @ApiProperty() + @IsString({ message: 'clientSecret must be in string format.' }) + clientSecret: string; + + @ApiProperty() + @IsString({ message: 'grantType must be in string format.' }) + grantType?: string = 'client_credentials'; +} diff --git a/apps/api-gateway/src/organization/organization.controller.ts b/apps/api-gateway/src/organization/organization.controller.ts index f07d44db5..6a99bf5cc 100644 --- a/apps/api-gateway/src/organization/organization.controller.ts +++ b/apps/api-gateway/src/organization/organization.controller.ts @@ -54,6 +54,7 @@ import { UserAccessGuard } from '../authz/guards/user-access-guard'; import { GetAllOrganizationsDto } from './dtos/get-organizations.dto'; import { PrimaryDid } from './dtos/set-primary-did.dto'; import { TrimStringParamPipe } from '@credebl/common/cast.helper'; +import { ClientTokenDto } from './dtos/client-token.dto'; @UseFilters(CustomExceptionFilter) @Controller('orgs') @@ -789,4 +790,16 @@ export class OrganizationController { }; return res.status(HttpStatus.OK).json(finalResponse); } + + @Post('/generateIssuerApiToken') + @ApiExcludeEndpoint() + @ApiOperation({ + summary: 'Generate API Token for the issuer', + description: 'Generate API Token for the issuer' + }) + @ApiResponse({ status: HttpStatus.OK, description: 'Success', type: ApiResponseDto }) + async generateApiToken(@Body() clientTokenDto: ClientTokenDto, @Res() res: Response): Promise { + const finalResponse = await this.organizationService.generateClientApiToken(clientTokenDto); + return res.status(HttpStatus.OK).header('Content-Type', 'application/json').send(finalResponse); + } } diff --git a/apps/api-gateway/src/organization/organization.service.ts b/apps/api-gateway/src/organization/organization.service.ts index d5928a653..72e1c89b4 100644 --- a/apps/api-gateway/src/organization/organization.service.ts +++ b/apps/api-gateway/src/organization/organization.service.ts @@ -24,6 +24,7 @@ import { GetAllOrganizationsDto } from './dtos/get-organizations.dto'; import { PrimaryDid } from './dtos/set-primary-did.dto'; import { NATSClient } from '@credebl/common/NATSClient'; import { ClientProxy } from '@nestjs/microservices'; +import { ClientTokenDto } from './dtos/client-token.dto'; @Injectable() export class OrganizationService extends BaseService { @@ -238,4 +239,7 @@ export class OrganizationService extends BaseService { const imageBuffer = Buffer.from(base64Data, 'base64'); return imageBuffer; } + async generateClientApiToken(clientTokenDto: ClientTokenDto): Promise<{ token: string }> { + return this.natsClient.sendNatsMessage(this.serviceProxy, 'generate-client-api-token', clientTokenDto); + } } diff --git a/apps/organization/dtos/client-token.dto.ts b/apps/organization/dtos/client-token.dto.ts new file mode 100644 index 000000000..52bb2e868 --- /dev/null +++ b/apps/organization/dtos/client-token.dto.ts @@ -0,0 +1,7 @@ +export class ClientTokenDto { + orgId: string; + clientAlias: string; + clientId: string; + clientSecret: string; + grantType?: string = 'client_credentials'; +} diff --git a/apps/organization/repositories/organization.repository.ts b/apps/organization/repositories/organization.repository.ts index deed11a4f..0cfa681d2 100644 --- a/apps/organization/repositories/organization.repository.ts +++ b/apps/organization/repositories/organization.repository.ts @@ -662,6 +662,7 @@ export class OrganizationRepository { countryId: true, stateId: true, cityId: true, + appLaunchDetails: true, userOrgRoles: { where: { orgRole: { diff --git a/apps/organization/src/organization.controller.ts b/apps/organization/src/organization.controller.ts index ca93335e0..72317bf03 100644 --- a/apps/organization/src/organization.controller.ts +++ b/apps/organization/src/organization.controller.ts @@ -4,12 +4,27 @@ import { OrganizationService } from './organization.service'; import { CreateOrganizationDto } from '../dtos/create-organization.dto'; import { BulkSendInvitationDto } from '../dtos/send-invitation.dto'; import { UpdateInvitationDto } from '../dtos/update-invitation.dt'; -import { IDidList, IGetOrgById, IGetOrganization, IOrgDetails, IUpdateOrganization, Payload } from '../interfaces/organization.interface'; -import { IOrgCredentials, IOrganizationInvitations, IOrganization, IOrganizationDashboard, IDeleteOrganization, IOrgActivityCount } from '@credebl/common/interfaces/organization.interface'; +import { + IDidList, + IGetOrgById, + IGetOrganization, + IOrgDetails, + IUpdateOrganization, + Payload +} from '../interfaces/organization.interface'; +import { + IOrgCredentials, + IOrganizationInvitations, + IOrganization, + IOrganizationDashboard, + IDeleteOrganization, + IOrgActivityCount +} from '@credebl/common/interfaces/organization.interface'; import { organisation, user } from '@prisma/client'; import { IAccessTokenData } from '@credebl/common/interfaces/interface'; import { IClientRoles } from '@credebl/client-registration/interfaces/client.interface'; import { IOrgRoles } from 'libs/org-roles/interfaces/org-roles.interface'; +import { ClientTokenDto } from '../dtos/client-token.dto'; @Controller() export class OrganizationController { @@ -23,7 +38,9 @@ export class OrganizationController { */ @MessagePattern({ cmd: 'create-organization' }) - async createOrganization(@Body() payload: { createOrgDto: CreateOrganizationDto; userId: string, keycloakUserId: string }): Promise { + async createOrganization( + @Body() payload: { createOrgDto: CreateOrganizationDto; userId: string; keycloakUserId: string } + ): Promise { return this.organizationService.createOrganization(payload.createOrgDto, payload.userId, payload.keycloakUserId); } @@ -34,17 +51,19 @@ export class OrganizationController { */ @MessagePattern({ cmd: 'set-primary-did' }) - async setPrimaryDid(@Body() payload: { orgId:string, did:string, id:string}): Promise { + async setPrimaryDid(@Body() payload: { orgId: string; did: string; id: string }): Promise { return this.organizationService.setPrimaryDid(payload.orgId, payload.did, payload.id); } /** - * - * @param payload + * + * @param payload * @returns organization client credentials */ @MessagePattern({ cmd: 'create-org-credentials' }) - async createOrgCredentials(@Body() payload: { orgId: string; userId: string, keycloakUserId: string }): Promise { + async createOrgCredentials( + @Body() payload: { orgId: string; userId: string; keycloakUserId: string } + ): Promise { return this.organizationService.createOrgCredentials(payload.orgId, payload.userId, payload.keycloakUserId); } @@ -55,7 +74,11 @@ export class OrganizationController { */ @MessagePattern({ cmd: 'update-organization' }) - async updateOrganization(payload: { updateOrgDto: IUpdateOrganization; userId: string, orgId: string }): Promise { + async updateOrganization(payload: { + updateOrgDto: IUpdateOrganization; + userId: string; + orgId: string; + }): Promise { return this.organizationService.updateOrganization(payload.updateOrgDto, payload.userId, payload.orgId); } @@ -65,7 +88,7 @@ export class OrganizationController { * @returns organization's did list */ @MessagePattern({ cmd: 'fetch-organization-dids' }) - async getOrgDidList(payload: {orgId:string}): Promise { + async getOrgDidList(payload: { orgId: string }): Promise { return this.organizationService.getOrgDidList(payload.orgId); } @@ -75,9 +98,7 @@ export class OrganizationController { * @returns Get created organization details */ @MessagePattern({ cmd: 'get-organizations' }) - async getOrganizations( - @Body() payload: { userId: string} & Payload - ): Promise { + async getOrganizations(@Body() payload: { userId: string } & Payload): Promise { const { userId, pageNumber, pageSize, search, role } = payload; return this.organizationService.getOrganizations(userId, pageNumber, pageSize, search, role); } @@ -87,12 +108,9 @@ export class OrganizationController { * @returns Get created organization details */ @MessagePattern({ cmd: 'get-organizations-count' }) - async countTotalOrgs( - @Body() payload: { userId: string} - ): Promise { - + async countTotalOrgs(@Body() payload: { userId: string }): Promise { const { userId } = payload; - + return this.organizationService.countTotalOrgs(userId); } @@ -100,9 +118,7 @@ export class OrganizationController { * @returns Get public organization details */ @MessagePattern({ cmd: 'get-public-organizations' }) - async getPublicOrganizations( - @Body() payload: Payload - ): Promise { + async getPublicOrganizations(@Body() payload: Payload): Promise { const { pageNumber, pageSize, search } = payload; return this.organizationService.getPublicOrganizations(pageNumber, pageSize, search); } @@ -113,13 +129,13 @@ export class OrganizationController { * @returns Get created organization details */ @MessagePattern({ cmd: 'get-organization-by-id' }) - async getOrganization(@Body() payload: { orgId: string; userId: string}): Promise { + async getOrganization(@Body() payload: { orgId: string; userId: string }): Promise { return this.organizationService.getOrganization(payload.orgId); } -/** - * @param orgSlug - * @returns organization details - */ + /** + * @param orgSlug + * @returns organization details + */ @MessagePattern({ cmd: 'get-organization-public-profile' }) async getPublicProfile(payload: { orgSlug }): Promise { return this.organizationService.getPublicProfile(payload); @@ -131,9 +147,7 @@ export class OrganizationController { * @returns Get created invitation details */ @MessagePattern({ cmd: 'get-invitations-by-orgId' }) - async getInvitationsByOrgId( - @Body() payload: { orgId: string } & Payload - ): Promise { + async getInvitationsByOrgId(@Body() payload: { orgId: string } & Payload): Promise { return this.organizationService.getInvitationsByOrgId( payload.orgId, payload.pageNumber, @@ -143,11 +157,11 @@ export class OrganizationController { } /** - * @returns Get org-roles + * @returns Get org-roles */ @MessagePattern({ cmd: 'get-org-roles' }) - async getOrgRoles(payload: {orgId: string, user: user}): Promise { + async getOrgRoles(payload: { orgId: string; user: user }): Promise { return this.organizationService.getOrgRoles(payload.orgId, payload.user); } @@ -163,7 +177,7 @@ export class OrganizationController { */ @MessagePattern({ cmd: 'send-invitation' }) async createInvitation( - @Body() payload: { bulkInvitationDto: BulkSendInvitationDto; userId: string, userEmail: string } + @Body() payload: { bulkInvitationDto: BulkSendInvitationDto; userId: string; userEmail: string } ): Promise { return this.organizationService.createInvitation(payload.bulkInvitationDto, payload.userId, payload.userEmail); } @@ -198,7 +212,7 @@ export class OrganizationController { */ @MessagePattern({ cmd: 'update-user-roles' }) - async updateUserRoles(payload: { orgId: string; roleIds: string[]; userId: string}): Promise { + async updateUserRoles(payload: { orgId: string; roleIds: string[]; userId: string }): Promise { return this.organizationService.updateUserRoles(payload.orgId, payload.roleIds, payload.userId); } @@ -212,9 +226,9 @@ export class OrganizationController { return this.organizationService.getOrganizationActivityCount(payload.orgId, payload.userId); } -/** - * @returns organization profile details - */ + /** + * @returns organization profile details + */ @MessagePattern({ cmd: 'fetch-organization-profile' }) async getOrgPofile(payload: { orgId: string }): Promise { return this.organizationService.getOrgPofile(payload.orgId); @@ -231,27 +245,27 @@ export class OrganizationController { } @MessagePattern({ cmd: 'get-organization-details' }) - async getOrgData(payload: { orgId: string; }): Promise { + async getOrgData(payload: { orgId: string }): Promise { return this.organizationService.getOrgDetails(payload.orgId); } - + @MessagePattern({ cmd: 'delete-organization' }) - async deleteOrganization(payload: { orgId: string, user: user }): Promise { + async deleteOrganization(payload: { orgId: string; user: user }): Promise { return this.organizationService.deleteOrganization(payload.orgId, payload.user); } @MessagePattern({ cmd: 'delete-org-client-credentials' }) - async deleteOrganizationCredentials(payload: { orgId: string, user: user }): Promise { + async deleteOrganizationCredentials(payload: { orgId: string; user: user }): Promise { return this.organizationService.deleteClientCredentials(payload.orgId, payload.user); } @MessagePattern({ cmd: 'delete-organization-invitation' }) - async deleteOrganizationInvitation(payload: { orgId: string; invitationId: string; }): Promise { + async deleteOrganizationInvitation(payload: { orgId: string; invitationId: string }): Promise { return this.organizationService.deleteOrganizationInvitation(payload.orgId, payload.invitationId); } @MessagePattern({ cmd: 'authenticate-client-credentials' }) - async clientLoginCredentails(payload: { clientId: string; clientSecret: string;}): Promise { + async clientLoginCredentails(payload: { clientId: string; clientSecret: string }): Promise { return this.organizationService.clientLoginCredentails(payload); } @@ -261,12 +275,12 @@ export class OrganizationController { } @MessagePattern({ cmd: 'get-agent-type-by-org-agent-type-id' }) - async getAgentTypeByAgentTypeId(payload: {orgAgentTypeId: string}): Promise { + async getAgentTypeByAgentTypeId(payload: { orgAgentTypeId: string }): Promise { return this.organizationService.getAgentTypeByAgentTypeId(payload.orgAgentTypeId); } @MessagePattern({ cmd: 'get-org-roles-details' }) - async getOrgRolesDetails(payload: {roleName: string}): Promise { + async getOrgRolesDetails(payload: { roleName: string }): Promise { return this.organizationService.getOrgRolesDetails(payload.roleName); } @@ -286,7 +300,12 @@ export class OrganizationController { } @MessagePattern({ cmd: 'get-org-agents-and-user-roles' }) - async getOrgAgentDetailsForEcosystem(payload: {orgIds: string[], search: string}): Promise { + async getOrgAgentDetailsForEcosystem(payload: { orgIds: string[]; search: string }): Promise { return this.organizationService.getOrgAgentDetailsForEcosystem(payload); } -} \ No newline at end of file + + @MessagePattern({ cmd: 'generate-client-api-token' }) + async generateClientApiToken(payload: ClientTokenDto): Promise<{ token: string }> { + return this.organizationService.generateClientApiToken(payload); + } +} diff --git a/apps/organization/src/organization.service.ts b/apps/organization/src/organization.service.ts index 0e6972fc8..51b89b93c 100644 --- a/apps/organization/src/organization.service.ts +++ b/apps/organization/src/organization.service.ts @@ -65,6 +65,7 @@ import { IOrgRoles } from 'libs/org-roles/interfaces/org-roles.interface'; import { NATSClient } from '@credebl/common/NATSClient'; import { UserRepository } from 'apps/user/repositories/user.repository'; import * as jwt from 'jsonwebtoken'; +import { ClientTokenDto } from '../dtos/client-token.dto'; @Injectable() export class OrganizationService { @@ -2029,4 +2030,70 @@ export class OrganizationService { throw new RpcException(error.response ? error.response : error); } } + + async generateClientApiToken(generateTokenDetails: ClientTokenDto): Promise<{ token: string }> { + try { + // Fetch organization and fail fast if not found + const orgDetails = await this.organizationRepository.getOrganizationDetails(generateTokenDetails.orgId); + if (!orgDetails) { + throw new NotFoundException(ResponseMessages.organisation.error.orgNotFound); + } + + // Compose keys + const clientIdKey = `${generateTokenDetails.clientAlias}_KEYCLOAK_MANAGEMENT_CLIENT_ID`; + const clientSecretKey = `${generateTokenDetails.clientAlias}_KEYCLOAK_MANAGEMENT_CLIENT_SECRET`; + + // Fetch env vars once + const encryptedClientId = process.env[clientIdKey]; + const encryptedClientSecret = process.env[clientSecretKey]; + + // Fail fast if not present + if (!encryptedClientId || !encryptedClientSecret) { + throw new NotFoundException(ResponseMessages.organisation.error.invalidClientCredentials); + } + + // Decrypt env vars once + const decryptedClientId = await this.commonService.decryptPassword(encryptedClientId); + if (!decryptedClientId) { + throw new NotFoundException(ResponseMessages.organisation.error.invalidClientCredentials); + } + const decryptedSecret = await this.commonService.decryptPassword(encryptedClientSecret); + if (!decryptedSecret) { + throw new NotFoundException(ResponseMessages.organisation.error.invalidClientCredentials); + } + + // Guard clauses for validation + if (generateTokenDetails.clientAlias.toLowerCase() !== decryptedClientId.toLowerCase()) { + throw new NotFoundException(ResponseMessages.organisation.error.invalidClientCredentials); + } + if (generateTokenDetails.clientSecret !== decryptedSecret) { + throw new NotFoundException(ResponseMessages.organisation.error.invalidClientCredentials); + } + + // Generate admin token + const adminTokenDetails = + await this.clientRegistrationService.generateTokenUsingAdminCredentials(generateTokenDetails); + if (!adminTokenDetails?.access_token) { + throw new InternalServerErrorException(ResponseMessages.organisation.error.adminTokenDetails); + } + + // Fetch client details + const clientDetails = await this.clientRegistrationService.fetchClientDetails( + generateTokenDetails.orgId, + adminTokenDetails.access_token + ); + if (!clientDetails?.length) { + throw new NotFoundException(ResponseMessages.organisation.error.clientDetails); + } + + // Authenticate client + const { secret } = clientDetails[0]; + const authenticationResult = await this.authenticateClientKeycloak(generateTokenDetails.orgId, secret); + + return { token: authenticationResult.access_token }; + } catch (error) { + this.logger.error(`in generating issuer api token: ${JSON.stringify(error)}`); + throw new RpcException(error.response || error); + } + } } diff --git a/libs/client-registration/src/client-registration.service.ts b/libs/client-registration/src/client-registration.service.ts index 51dbeb923..952439843 100644 --- a/libs/client-registration/src/client-registration.service.ts +++ b/libs/client-registration/src/client-registration.service.ts @@ -4,21 +4,23 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { BadRequestException, Injectable, Logger, NotFoundException, UnauthorizedException } from '@nestjs/common'; import * as qs from 'qs'; +import { BadRequestException, Injectable, Logger, NotFoundException, UnauthorizedException } from '@nestjs/common'; + import { ClientCredentialTokenPayloadDto } from './dtos/client-credential-token-payload.dto'; +import { ClientTokenDto } from './dtos/client-token.dto'; import { CommonConstants } from '@credebl/common/common.constant'; import { CommonService } from '@credebl/common'; import { CreateUserDto } from './dtos/create-user.dto'; +import { IClientRoles } from './interfaces/client.interface'; +import { IFormattedResponse } from '@credebl/common/interfaces/interface'; import { JwtService } from '@nestjs/jwt'; import { KeycloakUrlService } from '@credebl/keycloak-url'; -import { accessTokenPayloadDto } from './dtos/accessTokenPayloadDto'; -import { userTokenPayloadDto } from './dtos/userTokenPayloadDto'; import { KeycloakUserRegistrationDto } from 'apps/user/dtos/keycloak-register.dto'; import { ResponseMessages } from '@credebl/common/response-messages'; -import { IClientRoles } from './interfaces/client.interface'; -import { IFormattedResponse } from '@credebl/common/interfaces/interface'; +import { accessTokenPayloadDto } from './dtos/accessTokenPayloadDto'; +import { userTokenPayloadDto } from './dtos/userTokenPayloadDto'; @Injectable() export class ClientRegistrationService { @@ -721,4 +723,34 @@ export class ClientRegistrationService { return userInfo; } + + async generateTokenUsingAdminCredentials(clientDetails: ClientTokenDto) { + const realmName = process.env.KEYCLOAK_REALM; + const payload = { + client_id: clientDetails.clientId, + client_secret: clientDetails.clientSecret, + grant_type: clientDetails.grantType ?? 'client_credentials' + }; + const config = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }; + const generatedTokenDetails = await this.commonService.httpPost( + await this.keycloakUrlService.GetSATURL(realmName), + qs.stringify(payload), + config + ); + return generatedTokenDetails; + } + + async fetchClientDetails(clientId: string, token: string) { + const realmName = process.env.KEYCLOAK_REALM; + + const clientDetails = await this.commonService.httpGet( + await this.keycloakUrlService.GetClientURL(realmName, clientId), + this.getAuthHeader(token) + ); + return clientDetails; + } } diff --git a/libs/client-registration/src/dtos/client-token.dto.ts b/libs/client-registration/src/dtos/client-token.dto.ts new file mode 100644 index 000000000..0e1a8d644 --- /dev/null +++ b/libs/client-registration/src/dtos/client-token.dto.ts @@ -0,0 +1,6 @@ +export class ClientTokenDto { + orgId: string; + clientId: string; + clientSecret: string; + grantType?: string = 'client_credentials'; +} diff --git a/libs/common/src/response-messages/index.ts b/libs/common/src/response-messages/index.ts index 49308396c..8be466d1c 100644 --- a/libs/common/src/response-messages/index.ts +++ b/libs/common/src/response-messages/index.ts @@ -130,7 +130,10 @@ export const ResponseMessages = { primaryDid: 'This DID is already set to primary DID', didNotFound: 'DID does not exist in organiation', organizationNotFound: 'Organization not found', - MaximumOrgsLimit: 'Limit reached: You can be associated with or create maximum 10 organizations.' + MaximumOrgsLimit: 'Limit reached: You can be associated with or create maximum 10 organizations.', + adminTokenDetails: 'Error in generating admin token details', + clientDetails: 'Error in fetching client details', + invalidClientCredentials: 'Invalid client credentials' } }, diff --git a/libs/keycloak-url/src/keycloak-url.service.ts b/libs/keycloak-url/src/keycloak-url.service.ts index fc259d1c2..b3dab1b91 100644 --- a/libs/keycloak-url/src/keycloak-url.service.ts +++ b/libs/keycloak-url/src/keycloak-url.service.ts @@ -2,131 +2,73 @@ import { Injectable, Logger } from '@nestjs/common'; @Injectable() export class KeycloakUrlService { - private readonly logger = new Logger('KeycloakUrlService'); + private readonly logger = new Logger('KeycloakUrlService'); - - async createUserURL( - realm: string - ):Promise { - - return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/users`; - } - - async getUserByUsernameURL( - realm: string, - username: string - ):Promise { - - return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/users?username=${username}`; + async createUserURL(realm: string): Promise { + return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/users`; } - async GetUserInfoURL( - realm: string, - userid: string - ):Promise { - - return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/users/${userid}`; - } - - async GetSATURL( - realm: string - ):Promise { + async getUserByUsernameURL(realm: string, username: string): Promise { + return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/users?username=${username}`; + } - return `${process.env.KEYCLOAK_DOMAIN}realms/${realm}/protocol/openid-connect/token`; - } - - async ResetPasswordURL( - realm: string, - userid: string - ):Promise { + async GetUserInfoURL(realm: string, userid: string): Promise { + return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/users/${userid}`; + } - return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/users/${userid}/reset-password`; + async GetSATURL(realm: string): Promise { + return `${process.env.KEYCLOAK_DOMAIN}realms/${realm}/protocol/openid-connect/token`; } + async ResetPasswordURL(realm: string, userid: string): Promise { + return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/users/${userid}/reset-password`; + } - async CreateRealmURL():Promise { + async CreateRealmURL(): Promise { return `${process.env.KEYCLOAK_DOMAIN}admin/realms`; } - async createClientURL( - realm: string - ):Promise { - + async createClientURL(realm: string): Promise { return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/clients`; } - async GetClientURL( - realm: string, - clientid: string - ):Promise { - + async GetClientURL(realm: string, clientid: string): Promise { return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/clients?clientId=${clientid}`; - } - - async GetClientSecretURL( - realm: string, - clientid: string - ):Promise { + } + async GetClientSecretURL(realm: string, clientid: string): Promise { return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/clients/${clientid}/client-secret`; } - async GetClientRoleURL( - realm: string, - clientid: string, - roleName = '' - ):Promise { - + async GetClientRoleURL(realm: string, clientid: string, roleName = ''): Promise { if ('' === roleName) { return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/clients/${clientid}/roles`; } return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/clients/${clientid}/roles/${roleName}`; - } - async GetRealmRoleURL( - realm: string, - roleName = '' - ):Promise { - + async GetRealmRoleURL(realm: string, roleName = ''): Promise { if ('' === roleName) { return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/roles`; } return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/roles/${roleName}`; - } - async GetClientUserRoleURL( - realm: string, - userId: string, - clientId?: string - ):Promise { - + async GetClientUserRoleURL(realm: string, userId: string, clientId?: string): Promise { if (clientId) { return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/users/${userId}/role-mappings/clients/${clientId}`; } return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/users/${userId}/role-mappings/realm`; - } - - - async GetClientIdpURL( - realm: string, - idp: string - ):Promise { + async GetClientIdpURL(realm: string, idp: string): Promise { return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/clients/${idp}`; } - async GetClient( - realm: string, - clientId: string - ):Promise { - + async GetClient(realm: string, clientId: string): Promise { return `${process.env.KEYCLOAK_DOMAIN}admin/realms/${realm}/clients?clientId=${clientId}`; } - } diff --git a/libs/prisma-service/prisma/migrations/20250925060521_added_app_launch_details_column_in_organization/migration.sql b/libs/prisma-service/prisma/migrations/20250925060521_added_app_launch_details_column_in_organization/migration.sql new file mode 100644 index 000000000..595c14fa5 --- /dev/null +++ b/libs/prisma-service/prisma/migrations/20250925060521_added_app_launch_details_column_in_organization/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "organisation" ADD COLUMN "appLaunchDetails" JSONB; diff --git a/libs/prisma-service/prisma/schema.prisma b/libs/prisma-service/prisma/schema.prisma index 108ff614e..dfba4e1f4 100644 --- a/libs/prisma-service/prisma/schema.prisma +++ b/libs/prisma-service/prisma/schema.prisma @@ -133,6 +133,7 @@ model organisation { clientId String? @db.VarChar(500) clientSecret String? @db.VarChar(500) registrationNumber String? @db.VarChar(100) + appLaunchDetails Json? countryId Int? countries countries? @relation(fields: [countryId], references: [id]) stateId Int?