mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 19:28:16 +00:00
feat: greepy review
This commit is contained in:
@@ -14,8 +14,14 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.foreign("rootOrgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
t.foreign("rootOrgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
|
||||||
t.dropUnique(["slug"]);
|
t.dropUnique(["slug"]);
|
||||||
t.unique(["rootOrgId", "parentOrgId", "slug"]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// had to switch to raw for null not distinct
|
||||||
|
await knex.raw(`
|
||||||
|
ALTER TABLE "organization"
|
||||||
|
ADD CONSTRAINT "organization_root_parent_slug_unique"
|
||||||
|
UNIQUE ("rootOrgId", "parentOrgId", "slug") NULLS NOT DISTINCT;
|
||||||
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasIdentityOrgCol = await knex.schema.hasColumn(TableName.Identity, "orgId");
|
const hasIdentityOrgCol = await knex.schema.hasColumn(TableName.Identity, "orgId");
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export async function seed(knex: Knex): Promise<void> {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
id: seedData1.machineIdentity.id,
|
id: seedData1.machineIdentity.id,
|
||||||
name: seedData1.machineIdentity.name,
|
name: seedData1.machineIdentity.name,
|
||||||
authMethod: IdentityAuthMethod.UNIVERSAL_AUTH
|
authMethod: IdentityAuthMethod.UNIVERSAL_AUTH,
|
||||||
|
orgId: seedData1.organization.id
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
const identityUa = await knex(TableName.IdentityUniversalAuth)
|
const identityUa = await knex(TableName.IdentityUniversalAuth)
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import { OrganizationsSchema } from "@app/db/schemas";
|
|||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { ApiDocsTags, SUB_ORGANIZATIONS } from "@app/lib/api-docs";
|
import { ApiDocsTags, SUB_ORGANIZATIONS } from "@app/lib/api-docs";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { GenericResourceNameSchema } from "@app/server/lib/schemas";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { GenericResourceNameSchema } from "@app/server/lib/schemas";
|
|
||||||
|
|
||||||
const sanitiziedSubOrganizationSchema = OrganizationsSchema.pick({
|
const sanitizedSubOrganizationSchema = OrganizationsSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
name: true,
|
name: true,
|
||||||
slug: true,
|
slug: true,
|
||||||
@@ -26,7 +26,7 @@ export const registerSubOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
schema: {
|
schema: {
|
||||||
hide: false,
|
hide: false,
|
||||||
tags: [ApiDocsTags.SubOrganizations],
|
tags: [ApiDocsTags.SubOrganizations],
|
||||||
description: "Create a child organization",
|
description: "Create a sub organization",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
bearerAuth: []
|
bearerAuth: []
|
||||||
@@ -37,7 +37,7 @@ export const registerSubOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
organization: sanitiziedSubOrganizationSchema
|
organization: sanitizedSubOrganizationSchema
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -45,21 +45,14 @@ export const registerSubOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { organization } = await server.services.subOrganization.createSubOrg({
|
const { organization } = await server.services.subOrganization.createSubOrg({
|
||||||
name: req.body.name,
|
name: req.body.name,
|
||||||
permissionActor: {
|
permissionActor: req.permission
|
||||||
id: req.permission.id,
|
|
||||||
type: req.permission.type,
|
|
||||||
authMethod: req.permission.authMethod,
|
|
||||||
orgId: req.permission.orgId,
|
|
||||||
parentOrgId: req.permission.parentOrgId,
|
|
||||||
rootOrgId: req.permission.rootOrgId
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CREATE_CHILD_ORGANIZATION,
|
type: EventType.CREATE_SUB_ORGANIZATION,
|
||||||
metadata: {
|
metadata: {
|
||||||
name: req.body.name,
|
name: req.body.name,
|
||||||
organizationId: organization.id
|
organizationId: organization.id
|
||||||
@@ -80,7 +73,7 @@ export const registerSubOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
schema: {
|
schema: {
|
||||||
hide: false,
|
hide: false,
|
||||||
tags: [ApiDocsTags.SubOrganizations],
|
tags: [ApiDocsTags.SubOrganizations],
|
||||||
description: "List child organizations",
|
description: "List of sub organizations",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
bearerAuth: []
|
bearerAuth: []
|
||||||
@@ -97,21 +90,14 @@ export const registerSubOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
organizations: sanitiziedSubOrganizationSchema.array()
|
organizations: sanitizedSubOrganizationSchema.array()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { organizations } = await server.services.subOrganization.listSubOrgs({
|
const { organizations } = await server.services.subOrganization.listSubOrgs({
|
||||||
permissionActor: {
|
permissionActor: req.permission,
|
||||||
id: req.permission.id,
|
|
||||||
type: req.permission.type,
|
|
||||||
authMethod: req.permission.authMethod,
|
|
||||||
orgId: req.permission.orgId,
|
|
||||||
parentOrgId: req.permission.orgId,
|
|
||||||
rootOrgId: req.permission.rootOrgId
|
|
||||||
},
|
|
||||||
data: {
|
data: {
|
||||||
limit: req.query.limit,
|
limit: req.query.limit,
|
||||||
offset: req.query.offset,
|
offset: req.query.offset,
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ export enum EventType {
|
|||||||
UPDATE_TOKEN_IDENTITY_TOKEN_AUTH = "update-token-identity-token-auth",
|
UPDATE_TOKEN_IDENTITY_TOKEN_AUTH = "update-token-identity-token-auth",
|
||||||
GET_TOKENS_IDENTITY_TOKEN_AUTH = "get-tokens-identity-token-auth",
|
GET_TOKENS_IDENTITY_TOKEN_AUTH = "get-tokens-identity-token-auth",
|
||||||
|
|
||||||
CREATE_CHILD_ORGANIZATION = "create-child-organization",
|
CREATE_SUB_ORGANIZATION = "create-child-organization",
|
||||||
|
|
||||||
ADD_IDENTITY_TOKEN_AUTH = "add-identity-token-auth",
|
ADD_IDENTITY_TOKEN_AUTH = "add-identity-token-auth",
|
||||||
UPDATE_IDENTITY_TOKEN_AUTH = "update-identity-token-auth",
|
UPDATE_IDENTITY_TOKEN_AUTH = "update-identity-token-auth",
|
||||||
@@ -609,8 +609,8 @@ interface GetSecretsEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreateChildOrganizationEvent {
|
interface CreateSubOrganizationEvent {
|
||||||
type: EventType.CREATE_CHILD_ORGANIZATION;
|
type: EventType.CREATE_SUB_ORGANIZATION;
|
||||||
metadata: {
|
metadata: {
|
||||||
name: string;
|
name: string;
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
@@ -3873,7 +3873,7 @@ interface PamResourceDeleteEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type Event =
|
export type Event =
|
||||||
| CreateChildOrganizationEvent
|
| CreateSubOrganizationEvent
|
||||||
| GetSecretsEvent
|
| GetSecretsEvent
|
||||||
| GetSecretEvent
|
| GetSecretEvent
|
||||||
| CreateSecretEvent
|
| CreateSecretEvent
|
||||||
|
|||||||
@@ -212,9 +212,9 @@ export const permissionServiceFactory = ({
|
|||||||
const rootOrgId = permissionData?.[0]?.rootOrgId;
|
const rootOrgId = permissionData?.[0]?.rootOrgId;
|
||||||
const isChild = Boolean(rootOrgId);
|
const isChild = Boolean(rootOrgId);
|
||||||
if (scope === OrganizationActionScope.ParentOrganization && isChild) {
|
if (scope === OrganizationActionScope.ParentOrganization && isChild) {
|
||||||
throw new BadRequestError({ message: `Child organization cannot do this operation` });
|
throw new ForbiddenRequestError({ message: `Child organization cannot do this operation` });
|
||||||
} else if (scope === OrganizationActionScope.ChildOrganization && !isChild) {
|
} else if (scope === OrganizationActionScope.ChildOrganization && !isChild) {
|
||||||
throw new BadRequestError({ message: `Parent organization cannot do this operation` });
|
throw new ForbiddenRequestError({ message: `Parent organization cannot do this operation` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const permissionFromRoles = permissionData.flatMap((membership) => {
|
const permissionFromRoles = permissionData.flatMap((membership) => {
|
||||||
|
|||||||
@@ -719,12 +719,12 @@ export const ORGANIZATIONS = {
|
|||||||
|
|
||||||
export const SUB_ORGANIZATIONS = {
|
export const SUB_ORGANIZATIONS = {
|
||||||
CREATE: {
|
CREATE: {
|
||||||
name: "The name of the child organization to create."
|
name: "The name of the sub organization to create."
|
||||||
},
|
},
|
||||||
LIST: {
|
LIST: {
|
||||||
limit: "The number of child organizations to return.",
|
limit: "The number of sub organizations to return.",
|
||||||
offset: "The offset to start from. If you enter 10, it will start from the 10th child organization.",
|
offset: "The offset to start from. If you enter 10, it will start from the 10th sub organization.",
|
||||||
isAccessible: "Filter to only return child organizations that the actor has access to."
|
isAccessible: "Filter to only return sub organizations that the actor has access to."
|
||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import { TScimTokenJwtPayload } from "@app/ee/services/scim/scim-types";
|
|||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { GenericResourceNameSchema } from "@app/server/lib/schemas";
|
||||||
import { ActorType, AuthMethod, AuthMode, AuthModeJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
|
import { ActorType, AuthMethod, AuthMode, AuthModeJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-token/identity-access-token-types";
|
||||||
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
|
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
|
||||||
import { GenericResourceNameSchema } from "@app/server/lib/schemas";
|
|
||||||
|
|
||||||
export type TAuthMode =
|
export type TAuthMode =
|
||||||
| {
|
| {
|
||||||
@@ -243,7 +243,7 @@ export const injectIdentity = fp(
|
|||||||
requestContext.set("orgId", orgId);
|
requestContext.set("orgId", orgId);
|
||||||
|
|
||||||
if (subOrganizationSelector)
|
if (subOrganizationSelector)
|
||||||
throw new BadRequestError({ message: `Service token doesn't support sub organization selector` });
|
throw new BadRequestError({ message: `SCIM token doesn't support sub organization selector` });
|
||||||
|
|
||||||
req.auth = {
|
req.auth = {
|
||||||
authMode: AuthMode.SCIM_TOKEN,
|
authMode: AuthMode.SCIM_TOKEN,
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
|
|
||||||
if (subOrganizationSelector) {
|
if (subOrganizationSelector) {
|
||||||
const subOrganization = await orgDAL.findOne({ rootOrgId, slug: subOrganizationSelector });
|
const subOrganization = await orgDAL.findOne({ rootOrgId, slug: subOrganizationSelector });
|
||||||
if (!subOrganizationSelector)
|
if (!subOrganization)
|
||||||
throw new BadRequestError({ message: `Sub organization ${subOrganizationSelector} not found` });
|
throw new BadRequestError({ message: `Sub organization ${subOrganizationSelector} not found` });
|
||||||
|
|
||||||
const identityOrgMembership = await membershipIdentityDAL.findOne({
|
const identityOrgMembership = await membershipIdentityDAL.findOne({
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
|||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TIdentityDALFactory } from "../identity/identity-dal";
|
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
import { TOrgDALFactory } from "../org/org-dal";
|
import { TOrgDALFactory } from "../org/org-dal";
|
||||||
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
|
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ import {
|
|||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TIdentityDALFactory } from "../identity/identity-dal";
|
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
import { TOrgDALFactory } from "../org/org-dal";
|
import { TOrgDALFactory } from "../org/org-dal";
|
||||||
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
|
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ import {
|
|||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TIdentityDALFactory } from "../identity/identity-dal";
|
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
import { TOrgDALFactory } from "../org/org-dal";
|
import { TOrgDALFactory } from "../org/org-dal";
|
||||||
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
|
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ import {
|
|||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TIdentityDALFactory } from "../identity/identity-dal";
|
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
import { TOrgDALFactory } from "../org/org-dal";
|
import { TOrgDALFactory } from "../org/org-dal";
|
||||||
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
|
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { checkIPAgainstBlocklist, extractIPDetails, isValidIpOrCidr, TIp } from
|
|||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
@@ -41,7 +42,6 @@ import {
|
|||||||
TRevokeUaDTO,
|
TRevokeUaDTO,
|
||||||
TUpdateUaDTO
|
TUpdateUaDTO
|
||||||
} from "./identity-ua-types";
|
} from "./identity-ua-types";
|
||||||
import { TIdentityDALFactory } from "../identity/identity-dal";
|
|
||||||
|
|
||||||
type TIdentityUaServiceFactoryDep = {
|
type TIdentityUaServiceFactoryDep = {
|
||||||
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
@@ -314,10 +314,6 @@ export const identityUaServiceFactory = ({
|
|||||||
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
|
||||||
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessTokenMaxTTL > 0 && accessTokenTTL > accessTokenMaxTTL) {
|
if (accessTokenMaxTTL > 0 && accessTokenTTL > accessTokenMaxTTL) {
|
||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ export const membershipIdentityDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// this right nwo only support sub organization
|
// this right now only support sub organization
|
||||||
const listAvailableIdentities = async (orgId: string, rootOrgId: string) => {
|
const listAvailableIdentities = async (orgId: string, rootOrgId: string) => {
|
||||||
try {
|
try {
|
||||||
const usersConnectedToOrg = db
|
const usersConnectedToOrg = db
|
||||||
@@ -381,7 +381,7 @@ export const membershipIdentityDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
return docs;
|
return docs;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "ListAvailableUsers" });
|
throw new DatabaseError({ error, name: "ListAvailableIdentities" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export const newOrgMembershipIdentityFactory = ({
|
|||||||
|
|
||||||
const identityDetails = await identityDAL.findById(dto.data.identityId);
|
const identityDetails = await identityDAL.findById(dto.data.identityId);
|
||||||
if (identityDetails.orgId !== dto.permission.rootOrgId) {
|
if (identityDetails.orgId !== dto.permission.rootOrgId) {
|
||||||
throw new BadRequestError({ message: "Only identites from parent organization can be invited" });
|
throw new BadRequestError({ message: "Only identities from parent organization can be invited" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const permissionRoles = await permissionService.getOrgPermissionByRoles(
|
const permissionRoles = await permissionService.getOrgPermissionByRoles(
|
||||||
@@ -143,11 +143,11 @@ export const newOrgMembershipIdentityFactory = ({
|
|||||||
scope: OrganizationActionScope.ChildOrganization
|
scope: OrganizationActionScope.ChildOrganization
|
||||||
});
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Delete, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const identityDetails = await identityDAL.findById(dto.selector.identityId);
|
const identityDetails = await identityDAL.findById(dto.selector.identityId);
|
||||||
if (identityDetails.orgId !== dto.permission.rootOrgId) {
|
if (identityDetails.orgId !== dto.permission.rootOrgId) {
|
||||||
throw new BadRequestError({ message: "Only identites from parent organization can do this operation" });
|
throw new BadRequestError({ message: "Only identities from parent organization can do this operation" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (identityDetails.orgId === dto.permission.orgId) {
|
if (identityDetails.orgId === dto.permission.orgId) {
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// this right nwo only support sub organization
|
// this right now only support sub organization
|
||||||
const listAvailableUsers = async (orgId: string, rootOrgId: string) => {
|
const listAvailableUsers = async (orgId: string, rootOrgId: string) => {
|
||||||
try {
|
try {
|
||||||
const usersConnectedToOrg = db
|
const usersConnectedToOrg = db
|
||||||
|
|||||||
@@ -92,10 +92,15 @@ export const newOrgMembershipUserFactory = ({
|
|||||||
},
|
},
|
||||||
scopeOrgId: org.rootOrgId
|
scopeOrgId: org.rootOrgId
|
||||||
});
|
});
|
||||||
if (rootOrgMembership.length !== newMembers.length)
|
if (rootOrgMembership.length !== newMembers.length) {
|
||||||
|
const emails = newMembers
|
||||||
|
.filter((user) => !rootOrgMembership.find((i) => i.actorUserId === user.id))
|
||||||
|
.map((el) => el.email)
|
||||||
|
.join(",");
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "User doesn't have membership in root organization"
|
message: `Users with email ${emails} doesn't have membership in root organization`
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|||||||
|
|
||||||
import { apiRequest } from "@app/config/request";
|
import { apiRequest } from "@app/config/request";
|
||||||
|
|
||||||
|
import { identitiesKeys } from "../identities";
|
||||||
import {
|
import {
|
||||||
TCreateOrgIdentityMembershipDTO,
|
TCreateOrgIdentityMembershipDTO,
|
||||||
TDeleteOrgIdentityMembershipDTO,
|
TDeleteOrgIdentityMembershipDTO,
|
||||||
@@ -19,8 +20,7 @@ export const useCreateOrgIdentityMembership = () => {
|
|||||||
return data.identityMembership;
|
return data.identityMembership;
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
// Invalidate relevant queries if needed
|
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentities({ search: {} }) });
|
||||||
queryClient.invalidateQueries({ queryKey: ["organization"] });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -35,8 +35,7 @@ export const useDeleteOrgIdentityMembership = () => {
|
|||||||
return data.identityMembership;
|
return data.identityMembership;
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
// Invalidate relevant queries if needed
|
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentities({ search: {} }) });
|
||||||
queryClient.invalidateQueries({ queryKey: ["organization"] });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ export const Navbar = () => {
|
|||||||
size="xs"
|
size="xs"
|
||||||
className="flex w-full items-center justify-start p-0 font-normal"
|
className="flex w-full items-center justify-start p-0 font-normal"
|
||||||
leftIcon={
|
leftIcon={
|
||||||
currentOrg?.id === org.id && (
|
currentOrg?.parentOrgId === org.id && (
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faCheck}
|
icon={faCheck}
|
||||||
className="mr-3 text-primary"
|
className="mr-3 text-primary"
|
||||||
@@ -654,7 +654,7 @@ export const Navbar = () => {
|
|||||||
subTitle="Define a new sub-organization under your current organization."
|
subTitle="Define a new sub-organization under your current organization."
|
||||||
>
|
>
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<NewSubOrganizationForm onClose={() => setShowSubOrgForm(true)} />
|
<NewSubOrganizationForm onClose={() => setShowSubOrgForm(false)} />
|
||||||
</div>
|
</div>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { motion } from "framer-motion";
|
|||||||
|
|
||||||
import { CreateOrgModal } from "@app/components/organization/CreateOrgModal";
|
import { CreateOrgModal } from "@app/components/organization/CreateOrgModal";
|
||||||
import { Tab, TabList, Tabs } from "@app/components/v2";
|
import { Tab, TabList, Tabs } from "@app/components/v2";
|
||||||
import { usePopUp } from "@app/hooks";
|
|
||||||
import { useOrganization } from "@app/context";
|
import { useOrganization } from "@app/context";
|
||||||
|
import { usePopUp } from "@app/hooks";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isHidden?: boolean;
|
isHidden?: boolean;
|
||||||
|
|||||||
+1
-1
@@ -243,7 +243,7 @@ export const IdentitySection = withPermission(
|
|||||||
>
|
>
|
||||||
<ModalContent
|
<ModalContent
|
||||||
title="Assign Existing Identity"
|
title="Assign Existing Identity"
|
||||||
subTitle="Assign an existing identity from your organization or namespace to this project. The identity will continue to be managed at its original scope."
|
subTitle="Assign an existing identity from your root organization to the sub organization. The identity will continue to be managed at its original scope."
|
||||||
>
|
>
|
||||||
<IdentityLinkForm onClose={() => handlePopUpClose("linkIdentity")} />
|
<IdentityLinkForm onClose={() => handlePopUpClose("linkIdentity")} />
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
|
|||||||
+1
-1
@@ -370,7 +370,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
<Td>
|
<Td>
|
||||||
<p className="truncate">
|
<p className="truncate">
|
||||||
<FontAwesomeIcon size="sm" className="mr-1.5" icon={faBuilding} />
|
<FontAwesomeIcon size="sm" className="mr-1.5" icon={faBuilding} />
|
||||||
{currentOrg.id === orgId ? "Organization" : "Root Organization"}
|
{currentOrg.id === orgId ? "Sub Organization" : "Root Organization"}
|
||||||
</p>
|
</p>
|
||||||
</Td>
|
</Td>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
import { AppConnectionsPage } from "./AppConnectionsPage";
|
import { AppConnectionsPage } from "./AppConnectionsPage";
|
||||||
|
|
||||||
@@ -6,6 +7,11 @@ export const Route = createFileRoute(
|
|||||||
"/_authenticate/_inject-org-details/_org-layout/organization/app-connections/"
|
"/_authenticate/_inject-org-details/_org-layout/organization/app-connections/"
|
||||||
)({
|
)({
|
||||||
component: AppConnectionsPage,
|
component: AppConnectionsPage,
|
||||||
|
validateSearch: z.object({
|
||||||
|
error: z.string().optional(),
|
||||||
|
success: z.string().optional(),
|
||||||
|
connectionId: z.string().optional()
|
||||||
|
}),
|
||||||
context: () => ({
|
context: () => ({
|
||||||
breadcrumbs: [
|
breadcrumbs: [
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -145,7 +145,7 @@ export const IdentityDetailsSection = ({ identityId, handlePopUpOpen, isOrgIdent
|
|||||||
</div>
|
</div>
|
||||||
{isSubOrganization && (
|
{isSubOrganization && (
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<p className="text-sm font-medium text-mineshaft-300">Manage By</p>
|
<p className="text-sm font-medium text-mineshaft-300">Managed By</p>
|
||||||
<p className="text-sm text-mineshaft-300">
|
<p className="text-sm text-mineshaft-300">
|
||||||
{isOrgIdentity ? "Organization" : "Root Organization"}
|
{isOrgIdentity ? "Organization" : "Root Organization"}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Controller, useForm } from "react-hook-form";
|
|||||||
import { faCheck, faCopy, faRedo } from "@fortawesome/free-solid-svg-icons";
|
import { faCheck, faCopy, faRedo } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useSearch } from "@tanstack/react-router";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
@@ -22,7 +23,6 @@ import {
|
|||||||
import { useTimedReset } from "@app/hooks";
|
import { useTimedReset } from "@app/hooks";
|
||||||
import { useCreatePublicSharedSecret, useCreateSharedSecret } from "@app/hooks/api";
|
import { useCreatePublicSharedSecret, useCreateSharedSecret } from "@app/hooks/api";
|
||||||
import { SecretSharingAccessType } from "@app/hooks/api/secretSharing";
|
import { SecretSharingAccessType } from "@app/hooks/api/secretSharing";
|
||||||
import { useSearch } from "@tanstack/react-router";
|
|
||||||
|
|
||||||
// values in ms
|
// values in ms
|
||||||
const expiresInOptions = [
|
const expiresInOptions = [
|
||||||
|
|||||||
Reference in New Issue
Block a user