mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 13:27:46 +00:00
Merge pull request #4553 from Infisical/feat/add-support-for-org-relay-registration
feat: add support for org relay registration
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { RelaysSchema } from "@app/db/schemas";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
import { UnauthorizedError } from "@app/lib/errors";
|
||||||
import { writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { slugSchema } from "@app/server/lib/schemas";
|
import { slugSchema } 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";
|
||||||
@@ -89,14 +90,59 @@ export const registerRelayRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
throw new BadRequestError({
|
|
||||||
message: "Org relay registration is not yet supported"
|
|
||||||
});
|
|
||||||
|
|
||||||
return server.services.relay.registerRelay({
|
return server.services.relay.registerRelay({
|
||||||
...req.body,
|
...req.body,
|
||||||
identityId: req.permission.id,
|
identityId: req.permission.id,
|
||||||
orgId: req.permission.orgId
|
orgId: req.permission.orgId,
|
||||||
|
actorAuthMethod: req.permission.authMethod
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/",
|
||||||
|
schema: {
|
||||||
|
response: {
|
||||||
|
200: RelaysSchema.array()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
return server.services.relay.getRelays({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: "/:id",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
id: z.string()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: RelaysSchema
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
return server.services.relay.deleteRelay({
|
||||||
|
id: req.params.id,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -395,7 +395,8 @@ export const gatewayV2ServiceFactory = ({
|
|||||||
relayId: gateway.relayId,
|
relayId: gateway.relayId,
|
||||||
orgId: gateway.orgId,
|
orgId: gateway.orgId,
|
||||||
orgName: gateway.orgName,
|
orgName: gateway.orgName,
|
||||||
gatewayId
|
gatewayId,
|
||||||
|
gatewayName: gateway.name
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -508,7 +509,8 @@ export const gatewayV2ServiceFactory = ({
|
|||||||
const relayCredentials = await relayService.getCredentialsForGateway({
|
const relayCredentials = await relayService.getCredentialsForGateway({
|
||||||
relayName,
|
relayName,
|
||||||
orgId,
|
orgId,
|
||||||
gatewayId: gateway.id
|
gatewayId: gateway.id,
|
||||||
|
gatewayName: gateway.name
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -58,6 +58,13 @@ export enum OrgPermissionGatewayActions {
|
|||||||
AttachGateways = "attach-gateways"
|
AttachGateways = "attach-gateways"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum OrgPermissionRelayActions {
|
||||||
|
CreateRelays = "create-relays",
|
||||||
|
ListRelays = "list-relays",
|
||||||
|
EditRelays = "edit-relays",
|
||||||
|
DeleteRelays = "delete-relays"
|
||||||
|
}
|
||||||
|
|
||||||
export enum OrgPermissionIdentityActions {
|
export enum OrgPermissionIdentityActions {
|
||||||
Read = "read",
|
Read = "read",
|
||||||
Create = "create",
|
Create = "create",
|
||||||
@@ -109,6 +116,7 @@ export enum OrgPermissionSubjects {
|
|||||||
AppConnections = "app-connections",
|
AppConnections = "app-connections",
|
||||||
Kmip = "kmip",
|
Kmip = "kmip",
|
||||||
Gateway = "gateway",
|
Gateway = "gateway",
|
||||||
|
Relay = "relay",
|
||||||
SecretShare = "secret-share"
|
SecretShare = "secret-share"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,6 +144,7 @@ export type OrgPermissionSet =
|
|||||||
| [OrgPermissionAuditLogsActions, OrgPermissionSubjects.AuditLogs]
|
| [OrgPermissionAuditLogsActions, OrgPermissionSubjects.AuditLogs]
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.ProjectTemplates]
|
| [OrgPermissionActions, OrgPermissionSubjects.ProjectTemplates]
|
||||||
| [OrgPermissionGatewayActions, OrgPermissionSubjects.Gateway]
|
| [OrgPermissionGatewayActions, OrgPermissionSubjects.Gateway]
|
||||||
|
| [OrgPermissionRelayActions, OrgPermissionSubjects.Relay]
|
||||||
| [
|
| [
|
||||||
OrgPermissionAppConnectionActions,
|
OrgPermissionAppConnectionActions,
|
||||||
(
|
(
|
||||||
@@ -279,6 +288,12 @@ export const OrgPermissionSchema = z.discriminatedUnion("subject", [
|
|||||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionGatewayActions).describe(
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionGatewayActions).describe(
|
||||||
"Describe what action an entity can take."
|
"Describe what action an entity can take."
|
||||||
)
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z.literal(OrgPermissionSubjects.Relay).describe("The entity this permission pertains to."),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionRelayActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -383,6 +398,11 @@ const buildAdminPermission = () => {
|
|||||||
can(OrgPermissionGatewayActions.DeleteGateways, OrgPermissionSubjects.Gateway);
|
can(OrgPermissionGatewayActions.DeleteGateways, OrgPermissionSubjects.Gateway);
|
||||||
can(OrgPermissionGatewayActions.AttachGateways, OrgPermissionSubjects.Gateway);
|
can(OrgPermissionGatewayActions.AttachGateways, OrgPermissionSubjects.Gateway);
|
||||||
|
|
||||||
|
can(OrgPermissionRelayActions.ListRelays, OrgPermissionSubjects.Relay);
|
||||||
|
can(OrgPermissionRelayActions.CreateRelays, OrgPermissionSubjects.Relay);
|
||||||
|
can(OrgPermissionRelayActions.EditRelays, OrgPermissionSubjects.Relay);
|
||||||
|
can(OrgPermissionRelayActions.DeleteRelays, OrgPermissionSubjects.Relay);
|
||||||
|
|
||||||
can(OrgPermissionAdminConsoleAction.AccessAllProjects, OrgPermissionSubjects.AdminConsole);
|
can(OrgPermissionAdminConsoleAction.AccessAllProjects, OrgPermissionSubjects.AdminConsole);
|
||||||
|
|
||||||
can(OrgPermissionKmipActions.Setup, OrgPermissionSubjects.Kmip);
|
can(OrgPermissionKmipActions.Setup, OrgPermissionSubjects.Kmip);
|
||||||
@@ -445,6 +465,10 @@ const buildMemberPermission = () => {
|
|||||||
can(OrgPermissionGatewayActions.CreateGateways, OrgPermissionSubjects.Gateway);
|
can(OrgPermissionGatewayActions.CreateGateways, OrgPermissionSubjects.Gateway);
|
||||||
can(OrgPermissionGatewayActions.AttachGateways, OrgPermissionSubjects.Gateway);
|
can(OrgPermissionGatewayActions.AttachGateways, OrgPermissionSubjects.Gateway);
|
||||||
|
|
||||||
|
can(OrgPermissionRelayActions.ListRelays, OrgPermissionSubjects.Relay);
|
||||||
|
can(OrgPermissionRelayActions.CreateRelays, OrgPermissionSubjects.Relay);
|
||||||
|
can(OrgPermissionRelayActions.EditRelays, OrgPermissionSubjects.Relay);
|
||||||
|
|
||||||
can(OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates, OrgPermissionSubjects.MachineIdentityAuthTemplate);
|
can(OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates, OrgPermissionSubjects.MachineIdentityAuthTemplate);
|
||||||
can(
|
can(
|
||||||
OrgPermissionMachineIdentityAuthTemplateActions.UnlinkTemplates,
|
OrgPermissionMachineIdentityAuthTemplateActions.UnlinkTemplates,
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export const RELAY_CONNECTING_GATEWAY_INFO = "1.3.6.1.4.1.12345.100.3";
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
|
import { isIP } from "node:net";
|
||||||
|
|
||||||
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import * as x509 from "@peculiar/x509";
|
import * as x509 from "@peculiar/x509";
|
||||||
|
|
||||||
import { TRelays } from "@app/db/schemas";
|
import { TRelays } from "@app/db/schemas";
|
||||||
import { PgSqlLock } from "@app/keystore/keystore";
|
import { PgSqlLock } from "@app/keystore/keystore";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
|
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
|
||||||
import { constructPemChainFromCerts, prependCertToPemChain } from "@app/services/certificate/certificate-fns";
|
import { constructPemChainFromCerts, prependCertToPemChain } from "@app/services/certificate/certificate-fns";
|
||||||
import { CertExtendedKeyUsage, CertKeyAlgorithm, CertKeyUsage } from "@app/services/certificate/certificate-types";
|
import { CertExtendedKeyUsage, CertKeyAlgorithm, CertKeyUsage } from "@app/services/certificate/certificate-types";
|
||||||
import {
|
import {
|
||||||
@@ -14,11 +18,15 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
|||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
|
|
||||||
import { verifyHostInputValidity } from "../dynamic-secret/dynamic-secret-fns";
|
import { verifyHostInputValidity } from "../dynamic-secret/dynamic-secret-fns";
|
||||||
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
|
import { OrgPermissionRelayActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { createSshCert, createSshKeyPair } from "../ssh/ssh-certificate-authority-fns";
|
import { createSshCert, createSshKeyPair } from "../ssh/ssh-certificate-authority-fns";
|
||||||
import { SshCertType } from "../ssh/ssh-certificate-authority-types";
|
import { SshCertType } from "../ssh/ssh-certificate-authority-types";
|
||||||
import { SshCertKeyAlgorithm } from "../ssh-certificate/ssh-certificate-types";
|
import { SshCertKeyAlgorithm } from "../ssh-certificate/ssh-certificate-types";
|
||||||
import { TInstanceRelayConfigDALFactory } from "./instance-relay-config-dal";
|
import { TInstanceRelayConfigDALFactory } from "./instance-relay-config-dal";
|
||||||
import { TOrgRelayConfigDALFactory } from "./org-relay-config-dal";
|
import { TOrgRelayConfigDALFactory } from "./org-relay-config-dal";
|
||||||
|
import { RELAY_CONNECTING_GATEWAY_INFO } from "./relay-constants";
|
||||||
import { TRelayDALFactory } from "./relay-dal";
|
import { TRelayDALFactory } from "./relay-dal";
|
||||||
|
|
||||||
export type TRelayServiceFactory = ReturnType<typeof relayServiceFactory>;
|
export type TRelayServiceFactory = ReturnType<typeof relayServiceFactory>;
|
||||||
@@ -29,12 +37,16 @@ export const relayServiceFactory = ({
|
|||||||
instanceRelayConfigDAL,
|
instanceRelayConfigDAL,
|
||||||
orgRelayConfigDAL,
|
orgRelayConfigDAL,
|
||||||
relayDAL,
|
relayDAL,
|
||||||
kmsService
|
kmsService,
|
||||||
|
licenseService,
|
||||||
|
permissionService
|
||||||
}: {
|
}: {
|
||||||
instanceRelayConfigDAL: TInstanceRelayConfigDALFactory;
|
instanceRelayConfigDAL: TInstanceRelayConfigDALFactory;
|
||||||
orgRelayConfigDAL: TOrgRelayConfigDALFactory;
|
orgRelayConfigDAL: TOrgRelayConfigDALFactory;
|
||||||
relayDAL: TRelayDALFactory;
|
relayDAL: TRelayDALFactory;
|
||||||
kmsService: TKmsServiceFactory;
|
kmsService: TKmsServiceFactory;
|
||||||
|
licenseService: TLicenseServiceFactory;
|
||||||
|
permissionService: TPermissionServiceFactory;
|
||||||
}) => {
|
}) => {
|
||||||
const $getInstanceCAs = async () => {
|
const $getInstanceCAs = async () => {
|
||||||
const instanceConfig = await instanceRelayConfigDAL.transaction(async (tx) => {
|
const instanceConfig = await instanceRelayConfigDAL.transaction(async (tx) => {
|
||||||
@@ -639,8 +651,9 @@ export const relayServiceFactory = ({
|
|||||||
true
|
true
|
||||||
),
|
),
|
||||||
new x509.ExtendedKeyUsageExtension([x509.ExtendedKeyUsage[CertExtendedKeyUsage.SERVER_AUTH]], true),
|
new x509.ExtendedKeyUsageExtension([x509.ExtendedKeyUsage[CertExtendedKeyUsage.SERVER_AUTH]], true),
|
||||||
|
|
||||||
// san
|
// san
|
||||||
new x509.SubjectAlternativeNameExtension([{ type: "ip", value: host }], false)
|
new x509.SubjectAlternativeNameExtension([{ type: isIP(host) ? "ip" : "dns", value: host }], false)
|
||||||
];
|
];
|
||||||
|
|
||||||
const relayServerSerialNumber = createSerialNumber();
|
const relayServerSerialNumber = createSerialNumber();
|
||||||
@@ -689,6 +702,7 @@ export const relayServiceFactory = ({
|
|||||||
|
|
||||||
const $generateRelayClientCredentials = async ({
|
const $generateRelayClientCredentials = async ({
|
||||||
gatewayId,
|
gatewayId,
|
||||||
|
gatewayName,
|
||||||
orgId,
|
orgId,
|
||||||
orgName,
|
orgName,
|
||||||
relayPkiClientCaCertificate,
|
relayPkiClientCaCertificate,
|
||||||
@@ -697,6 +711,7 @@ export const relayServiceFactory = ({
|
|||||||
relayPkiServerCaCertificateChain
|
relayPkiServerCaCertificateChain
|
||||||
}: {
|
}: {
|
||||||
gatewayId: string;
|
gatewayId: string;
|
||||||
|
gatewayName: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
orgName: string;
|
orgName: string;
|
||||||
relayPkiClientCaCertificate: Buffer;
|
relayPkiClientCaCertificate: Buffer;
|
||||||
@@ -727,6 +742,16 @@ export const relayServiceFactory = ({
|
|||||||
const clientCertPrivateKey = crypto.nativeCrypto.KeyObject.from(clientKeys.privateKey);
|
const clientCertPrivateKey = crypto.nativeCrypto.KeyObject.from(clientKeys.privateKey);
|
||||||
const clientCertSerialNumber = createSerialNumber();
|
const clientCertSerialNumber = createSerialNumber();
|
||||||
|
|
||||||
|
const connectingGatewayInfoExtension = new x509.Extension(
|
||||||
|
RELAY_CONNECTING_GATEWAY_INFO,
|
||||||
|
false,
|
||||||
|
Buffer.from(
|
||||||
|
JSON.stringify({
|
||||||
|
name: gatewayName
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
// Build standard extensions
|
// Build standard extensions
|
||||||
const extensions: x509.Extension[] = [
|
const extensions: x509.Extension[] = [
|
||||||
new x509.BasicConstraintsExtension(false),
|
new x509.BasicConstraintsExtension(false),
|
||||||
@@ -740,7 +765,8 @@ export const relayServiceFactory = ({
|
|||||||
x509.KeyUsageFlags[CertKeyUsage.KEY_AGREEMENT],
|
x509.KeyUsageFlags[CertKeyUsage.KEY_AGREEMENT],
|
||||||
true
|
true
|
||||||
),
|
),
|
||||||
new x509.ExtendedKeyUsageExtension([x509.ExtendedKeyUsage[CertExtendedKeyUsage.CLIENT_AUTH]], true)
|
new x509.ExtendedKeyUsageExtension([x509.ExtendedKeyUsage[CertExtendedKeyUsage.CLIENT_AUTH]], true),
|
||||||
|
connectingGatewayInfoExtension
|
||||||
];
|
];
|
||||||
|
|
||||||
const clientCert = await x509.X509CertificateGenerator.create({
|
const clientCert = await x509.X509CertificateGenerator.create({
|
||||||
@@ -768,11 +794,13 @@ export const relayServiceFactory = ({
|
|||||||
const getCredentialsForGateway = async ({
|
const getCredentialsForGateway = async ({
|
||||||
relayName,
|
relayName,
|
||||||
orgId,
|
orgId,
|
||||||
gatewayId
|
gatewayId,
|
||||||
|
gatewayName
|
||||||
}: {
|
}: {
|
||||||
relayName: string;
|
relayName: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
gatewayId: string;
|
gatewayId: string;
|
||||||
|
gatewayName: string;
|
||||||
}) => {
|
}) => {
|
||||||
let relay: TRelays | null = await relayDAL.findOne({
|
let relay: TRelays | null = await relayDAL.findOne({
|
||||||
orgId,
|
orgId,
|
||||||
@@ -819,10 +847,10 @@ export const relayServiceFactory = ({
|
|||||||
const relayClientSshCert = await createSshCert({
|
const relayClientSshCert = await createSshCert({
|
||||||
caPrivateKey: orgCAs.relaySshClientCaPrivateKey.toString("utf8"),
|
caPrivateKey: orgCAs.relaySshClientCaPrivateKey.toString("utf8"),
|
||||||
clientPublicKey: relayClientSshPublicKey,
|
clientPublicKey: relayClientSshPublicKey,
|
||||||
keyId: `relay-client-${relay.id}`,
|
keyId: `client-${relayName}`,
|
||||||
principals: [gatewayId],
|
principals: [gatewayId, gatewayName],
|
||||||
certType: SshCertType.USER,
|
certType: SshCertType.USER,
|
||||||
requestedTtl: "30d"
|
requestedTtl: "1d"
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -837,12 +865,14 @@ export const relayServiceFactory = ({
|
|||||||
relayId,
|
relayId,
|
||||||
orgId,
|
orgId,
|
||||||
orgName,
|
orgName,
|
||||||
gatewayId
|
gatewayId,
|
||||||
|
gatewayName
|
||||||
}: {
|
}: {
|
||||||
relayId: string;
|
relayId: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
orgName: string;
|
orgName: string;
|
||||||
gatewayId: string;
|
gatewayId: string;
|
||||||
|
gatewayName: string;
|
||||||
}) => {
|
}) => {
|
||||||
const relay = await relayDAL.findOne({
|
const relay = await relayDAL.findOne({
|
||||||
id: relayId
|
id: relayId
|
||||||
@@ -860,6 +890,7 @@ export const relayServiceFactory = ({
|
|||||||
const instanceCAs = await $getInstanceCAs();
|
const instanceCAs = await $getInstanceCAs();
|
||||||
const relayCertificateCredentials = await $generateRelayClientCredentials({
|
const relayCertificateCredentials = await $generateRelayClientCredentials({
|
||||||
gatewayId,
|
gatewayId,
|
||||||
|
gatewayName,
|
||||||
orgId,
|
orgId,
|
||||||
orgName,
|
orgName,
|
||||||
relayPkiClientCaCertificate: instanceCAs.instanceRelayPkiClientCaCertificate,
|
relayPkiClientCaCertificate: instanceCAs.instanceRelayPkiClientCaCertificate,
|
||||||
@@ -877,6 +908,7 @@ export const relayServiceFactory = ({
|
|||||||
const orgCAs = await $getOrgCAs(orgId);
|
const orgCAs = await $getOrgCAs(orgId);
|
||||||
const relayCertificateCredentials = await $generateRelayClientCredentials({
|
const relayCertificateCredentials = await $generateRelayClientCredentials({
|
||||||
gatewayId,
|
gatewayId,
|
||||||
|
gatewayName,
|
||||||
orgId,
|
orgId,
|
||||||
orgName,
|
orgName,
|
||||||
relayPkiClientCaCertificate: orgCAs.relayPkiClientCaCertificate,
|
relayPkiClientCaCertificate: orgCAs.relayPkiClientCaCertificate,
|
||||||
@@ -895,11 +927,13 @@ export const relayServiceFactory = ({
|
|||||||
host,
|
host,
|
||||||
name,
|
name,
|
||||||
identityId,
|
identityId,
|
||||||
|
actorAuthMethod,
|
||||||
orgId
|
orgId
|
||||||
}: {
|
}: {
|
||||||
host: string;
|
host: string;
|
||||||
name: string;
|
name: string;
|
||||||
identityId?: string;
|
identityId?: string;
|
||||||
|
actorAuthMethod?: ActorAuthMethod;
|
||||||
orgId?: string;
|
orgId?: string;
|
||||||
}) => {
|
}) => {
|
||||||
let relay: TRelays;
|
let relay: TRelays;
|
||||||
@@ -908,6 +942,27 @@ export const relayServiceFactory = ({
|
|||||||
await verifyHostInputValidity(host);
|
await verifyHostInputValidity(host);
|
||||||
|
|
||||||
if (isOrgRelay) {
|
if (isOrgRelay) {
|
||||||
|
const orgLicensePlan = await licenseService.getPlan(orgId);
|
||||||
|
if (!orgLicensePlan.gateway) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message:
|
||||||
|
"Relay registration failed due to organization plan restrictions. Please upgrade your instance to Infisical's Enterprise plan."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
ActorType.IDENTITY,
|
||||||
|
identityId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod!,
|
||||||
|
orgId
|
||||||
|
);
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
OrgPermissionRelayActions.CreateRelays,
|
||||||
|
OrgPermissionSubjects.Relay
|
||||||
|
);
|
||||||
|
|
||||||
relay = await relayDAL.transaction(async (tx) => {
|
relay = await relayDAL.transaction(async (tx) => {
|
||||||
const existingRelay = await relayDAL.findOne(
|
const existingRelay = await relayDAL.findOne(
|
||||||
{
|
{
|
||||||
@@ -995,9 +1050,75 @@ export const relayServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getRelays = async ({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
}: {
|
||||||
|
actorId: string;
|
||||||
|
actor: ActorType;
|
||||||
|
actorAuthMethod: ActorAuthMethod;
|
||||||
|
actorOrgId: string;
|
||||||
|
}) => {
|
||||||
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionRelayActions.ListRelays, OrgPermissionSubjects.Relay);
|
||||||
|
|
||||||
|
const instanceRelays = await relayDAL.find({
|
||||||
|
orgId: null
|
||||||
|
});
|
||||||
|
|
||||||
|
const orgRelays = await relayDAL.find({
|
||||||
|
orgId: actorOrgId
|
||||||
|
});
|
||||||
|
|
||||||
|
return [...instanceRelays, ...orgRelays];
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteRelay = async ({
|
||||||
|
id,
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
actorId: string;
|
||||||
|
actor: ActorType;
|
||||||
|
actorAuthMethod: ActorAuthMethod;
|
||||||
|
actorOrgId: string;
|
||||||
|
}) => {
|
||||||
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionRelayActions.DeleteRelays, OrgPermissionSubjects.Relay);
|
||||||
|
|
||||||
|
const relay = await relayDAL.findById(id);
|
||||||
|
if (!relay || relay.orgId !== actorOrgId || relay.orgId === null) {
|
||||||
|
throw new NotFoundError({ message: "Relay not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const deletedRelay = await relayDAL.deleteById(id);
|
||||||
|
return deletedRelay;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
registerRelay,
|
registerRelay,
|
||||||
getCredentialsForGateway,
|
getCredentialsForGateway,
|
||||||
getCredentialsForClient
|
getCredentialsForClient,
|
||||||
|
getRelays,
|
||||||
|
deleteRelay
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1110,7 +1110,9 @@ export const registerRoutes = async (
|
|||||||
instanceRelayConfigDAL,
|
instanceRelayConfigDAL,
|
||||||
orgRelayConfigDAL,
|
orgRelayConfigDAL,
|
||||||
relayDAL,
|
relayDAL,
|
||||||
kmsService
|
kmsService,
|
||||||
|
licenseService,
|
||||||
|
permissionService
|
||||||
});
|
});
|
||||||
|
|
||||||
const gatewayV2Service = gatewayV2ServiceFactory({
|
const gatewayV2Service = gatewayV2ServiceFactory({
|
||||||
|
|||||||
@@ -218,6 +218,15 @@ Supports conditions and permission inversion
|
|||||||
| `delete-gateways` | Remove gateways from organization |
|
| `delete-gateways` | Remove gateways from organization |
|
||||||
| `attach-gateways` | Attach gateways to resources |
|
| `attach-gateways` | Attach gateways to resources |
|
||||||
|
|
||||||
|
#### Subject: `relay`
|
||||||
|
|
||||||
|
| Action | Description |
|
||||||
|
| --------------- | ------------------------------- |
|
||||||
|
| `list-relays` | View all organization relays |
|
||||||
|
| `create-relays` | Add new relays to organization |
|
||||||
|
| `edit-relays` | Modify existing relay settings |
|
||||||
|
| `delete-relays` | Remove relays from organization |
|
||||||
|
|
||||||
#### Subject: `machine-identity-auth-template`
|
#### Subject: `machine-identity-auth-template`
|
||||||
|
|
||||||
| Action | Description |
|
| Action | Description |
|
||||||
|
|||||||
@@ -21,6 +21,13 @@ export enum OrgGatewayPermissionActions {
|
|||||||
AttachGateways = "attach-gateways"
|
AttachGateways = "attach-gateways"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum OrgRelayPermissionActions {
|
||||||
|
CreateRelays = "create-relays",
|
||||||
|
ListRelays = "list-relays",
|
||||||
|
EditRelays = "edit-relays",
|
||||||
|
DeleteRelays = "delete-relays"
|
||||||
|
}
|
||||||
|
|
||||||
export enum OrgPermissionMachineIdentityAuthTemplateActions {
|
export enum OrgPermissionMachineIdentityAuthTemplateActions {
|
||||||
ListTemplates = "list-templates",
|
ListTemplates = "list-templates",
|
||||||
CreateTemplates = "create-templates",
|
CreateTemplates = "create-templates",
|
||||||
@@ -51,6 +58,7 @@ export enum OrgPermissionSubjects {
|
|||||||
AppConnections = "app-connections",
|
AppConnections = "app-connections",
|
||||||
Kmip = "kmip",
|
Kmip = "kmip",
|
||||||
Gateway = "gateway",
|
Gateway = "gateway",
|
||||||
|
Relay = "relay",
|
||||||
SecretShare = "secret-share",
|
SecretShare = "secret-share",
|
||||||
GithubOrgSync = "github-org-sync",
|
GithubOrgSync = "github-org-sync",
|
||||||
GithubOrgSyncManual = "github-org-sync-manual",
|
GithubOrgSyncManual = "github-org-sync-manual",
|
||||||
@@ -135,6 +143,7 @@ export type OrgPermissionSet =
|
|||||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||||
]
|
]
|
||||||
| [OrgGatewayPermissionActions, OrgPermissionSubjects.Gateway]
|
| [OrgGatewayPermissionActions, OrgPermissionSubjects.Gateway]
|
||||||
|
| [OrgRelayPermissionActions, OrgPermissionSubjects.Relay]
|
||||||
| [OrgPermissionSecretShareAction, OrgPermissionSubjects.SecretShare]
|
| [OrgPermissionSecretShareAction, OrgPermissionSubjects.SecretShare]
|
||||||
| [
|
| [
|
||||||
OrgPermissionAppConnectionActions,
|
OrgPermissionAppConnectionActions,
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export * from "./mutations";
|
||||||
|
export * from "./queries";
|
||||||
|
export * from "./types";
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
import { apiRequest } from "@app/config/request";
|
||||||
|
|
||||||
|
import { relayQueryKeys } from "./queries";
|
||||||
|
|
||||||
|
export const useDeleteRelayById = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => {
|
||||||
|
return apiRequest.delete(`/api/v1/relays/${id}`);
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: relayQueryKeys.list() });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
import { apiRequest } from "@app/config/request";
|
||||||
|
|
||||||
|
import { TRelay } from "./types";
|
||||||
|
|
||||||
|
export const relayQueryKeys = {
|
||||||
|
list: () => ["relays"] as const
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchRelays = async (): Promise<TRelay[]> => {
|
||||||
|
const { data } = await apiRequest.get<TRelay[]>("/api/v1/relays");
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGetRelays = () => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: relayQueryKeys.list(),
|
||||||
|
queryFn: fetchRelays
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
export type TRelay = {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
orgId: string | null;
|
||||||
|
identityId: string | null;
|
||||||
|
name: string;
|
||||||
|
host: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TDeleteRelayDTO = {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
faInfinity,
|
faInfinity,
|
||||||
faMoneyBill,
|
faMoneyBill,
|
||||||
faPlug,
|
faPlug,
|
||||||
|
faRoute,
|
||||||
faShare,
|
faShare,
|
||||||
faTable,
|
faTable,
|
||||||
faUsers,
|
faUsers,
|
||||||
@@ -136,6 +137,18 @@ export const OrgSidebar = ({ isHidden }: Props) => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
|
<Link to="/organization/relays">
|
||||||
|
{({ isActive }) => (
|
||||||
|
<MenuItem isSelected={isActive}>
|
||||||
|
<div className="mx-1 flex gap-2">
|
||||||
|
<div className="w-6">
|
||||||
|
<FontAwesomeIcon icon={faRoute} className="mr-4" />
|
||||||
|
</div>
|
||||||
|
Relays
|
||||||
|
</div>
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
</MenuGroup>
|
</MenuGroup>
|
||||||
</Menu>
|
</Menu>
|
||||||
<div className="flex-grow" />
|
<div className="flex-grow" />
|
||||||
|
|||||||
@@ -0,0 +1,214 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { Helmet } from "react-helmet";
|
||||||
|
import {
|
||||||
|
faArrowUpRightFromSquare,
|
||||||
|
faBookOpen,
|
||||||
|
faCopy,
|
||||||
|
faDoorClosed,
|
||||||
|
faEllipsisV,
|
||||||
|
faMagnifyingGlass,
|
||||||
|
faSearch,
|
||||||
|
faTrash
|
||||||
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { formatRelative } from "date-fns";
|
||||||
|
|
||||||
|
import { createNotification } from "@app/components/notifications";
|
||||||
|
import { OrgPermissionCan } from "@app/components/permissions";
|
||||||
|
import {
|
||||||
|
DeleteActionModal,
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
EmptyState,
|
||||||
|
IconButton,
|
||||||
|
Input,
|
||||||
|
PageHeader,
|
||||||
|
Table,
|
||||||
|
TableContainer,
|
||||||
|
TableSkeleton,
|
||||||
|
TBody,
|
||||||
|
Td,
|
||||||
|
Th,
|
||||||
|
THead,
|
||||||
|
Tooltip,
|
||||||
|
Tr
|
||||||
|
} from "@app/components/v2";
|
||||||
|
import {
|
||||||
|
OrgPermissionSubjects,
|
||||||
|
OrgRelayPermissionActions
|
||||||
|
} from "@app/context/OrgPermissionContext/types";
|
||||||
|
import { withPermission } from "@app/hoc";
|
||||||
|
import { usePopUp } from "@app/hooks";
|
||||||
|
import { useDeleteRelayById, useGetRelays } from "@app/hooks/api/relays";
|
||||||
|
|
||||||
|
export const RelayListPage = withPermission(
|
||||||
|
() => {
|
||||||
|
const [search, setSearch] = useState("");
|
||||||
|
const { data: relays, isPending: isRelaysLoading } = useGetRelays();
|
||||||
|
|
||||||
|
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["deleteRelay"] as const);
|
||||||
|
|
||||||
|
const deleteRelayById = useDeleteRelayById();
|
||||||
|
|
||||||
|
const handleDeleteRelay = async () => {
|
||||||
|
const data = popUp.deleteRelay.data as { id: string };
|
||||||
|
await deleteRelayById.mutateAsync(data.id);
|
||||||
|
|
||||||
|
handlePopUpToggle("deleteRelay");
|
||||||
|
createNotification({
|
||||||
|
type: "success",
|
||||||
|
text: "Successfully deleted relay"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredRelays = relays?.filter((el) =>
|
||||||
|
el.name.toLowerCase().includes(search.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-bunker-800">
|
||||||
|
<Helmet>
|
||||||
|
<title>Infisical | Relays</title>
|
||||||
|
<meta property="og:image" content="/images/message.png" />
|
||||||
|
</Helmet>
|
||||||
|
<div className="flex w-full justify-center bg-bunker-800 text-white">
|
||||||
|
<div className="w-full max-w-7xl">
|
||||||
|
<PageHeader
|
||||||
|
className="w-full"
|
||||||
|
title={
|
||||||
|
<div className="flex w-full items-center">
|
||||||
|
<span>Relays</span>
|
||||||
|
<a
|
||||||
|
className="-mt-1.5"
|
||||||
|
href="https://infisical.com/docs/documentation/platform/relays/overview"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<div className="ml-2 inline-block rounded-md bg-yellow/20 px-1.5 text-sm font-normal text-yellow opacity-80 hover:opacity-100">
|
||||||
|
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
|
||||||
|
<span>Docs</span>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faArrowUpRightFromSquare}
|
||||||
|
className="mb-[0.07rem] ml-1.5 text-[10px]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
description="Create and configure relays to securely access private network resources from Infisical"
|
||||||
|
/>
|
||||||
|
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||||
|
<div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Input
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
|
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
|
||||||
|
placeholder="Search relay..."
|
||||||
|
className="flex-1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<TableContainer className="mt-4">
|
||||||
|
<Table>
|
||||||
|
<THead>
|
||||||
|
<Tr>
|
||||||
|
<Th className="w-1/3">Name</Th>
|
||||||
|
<Th>Host</Th>
|
||||||
|
<Th>Created</Th>
|
||||||
|
<Th className="w-5" />
|
||||||
|
</Tr>
|
||||||
|
</THead>
|
||||||
|
<TBody>
|
||||||
|
{isRelaysLoading && (
|
||||||
|
<TableSkeleton innerKey="relay-table" columns={4} key="relay-table" />
|
||||||
|
)}
|
||||||
|
{filteredRelays?.map((el) => (
|
||||||
|
<Tr key={el.id}>
|
||||||
|
<Td>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span>{el.name}</span>
|
||||||
|
{!el.orgId && (
|
||||||
|
<Tooltip content="This is an instance-level relay available to all organizations">
|
||||||
|
<span className="rounded bg-mineshaft-700 px-1.5 py-0.5 text-xs text-mineshaft-400">
|
||||||
|
Instance
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Td>
|
||||||
|
<Td>{el.host}</Td>
|
||||||
|
<Td>{formatRelative(new Date(el.createdAt), new Date())}</Td>
|
||||||
|
<Td className="w-5">
|
||||||
|
<Tooltip className="max-w-sm text-center" content="Options">
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<IconButton
|
||||||
|
ariaLabel="Options"
|
||||||
|
colorSchema="secondary"
|
||||||
|
className="w-6"
|
||||||
|
variant="plain"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faEllipsisV} />
|
||||||
|
</IconButton>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end">
|
||||||
|
<DropdownMenuItem
|
||||||
|
icon={<FontAwesomeIcon icon={faCopy} />}
|
||||||
|
onClick={() => navigator.clipboard.writeText(el.id)}
|
||||||
|
>
|
||||||
|
Copy ID
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<OrgPermissionCan
|
||||||
|
I={OrgRelayPermissionActions.DeleteRelays}
|
||||||
|
a={OrgPermissionSubjects.Relay}
|
||||||
|
>
|
||||||
|
{(isAllowed: boolean) => (
|
||||||
|
<DropdownMenuItem
|
||||||
|
isDisabled={!isAllowed || !el.orgId}
|
||||||
|
icon={<FontAwesomeIcon icon={faTrash} />}
|
||||||
|
className="text-red"
|
||||||
|
onClick={() => handlePopUpOpen("deleteRelay", el)}
|
||||||
|
>
|
||||||
|
Delete Relay
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
|
</OrgPermissionCan>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</Tooltip>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
))}
|
||||||
|
</TBody>
|
||||||
|
</Table>
|
||||||
|
{!isRelaysLoading && !filteredRelays?.length && (
|
||||||
|
<EmptyState
|
||||||
|
title={
|
||||||
|
relays?.length
|
||||||
|
? "No Relays match search..."
|
||||||
|
: "No Relays have been configured"
|
||||||
|
}
|
||||||
|
icon={relays?.length ? faSearch : faDoorClosed}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<DeleteActionModal
|
||||||
|
isOpen={popUp.deleteRelay.isOpen}
|
||||||
|
title={`Are you sure you want to delete relay ${
|
||||||
|
(popUp?.deleteRelay?.data as { name: string })?.name || ""
|
||||||
|
}?`}
|
||||||
|
onChange={(isOpen) => handlePopUpToggle("deleteRelay", isOpen)}
|
||||||
|
deleteKey="confirm"
|
||||||
|
onDeleteApproved={() => handleDeleteRelay()}
|
||||||
|
/>
|
||||||
|
</TableContainer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ action: OrgRelayPermissionActions.ListRelays, subject: OrgPermissionSubjects.Relay }
|
||||||
|
);
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
import { RelayListPage } from "./RelayListPage";
|
||||||
|
|
||||||
|
export const Route = createFileRoute(
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/relays/"
|
||||||
|
)({
|
||||||
|
component: RelayListPage,
|
||||||
|
context: () => ({
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
label: "Relays"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
+12
-1
@@ -11,7 +11,8 @@ import {
|
|||||||
OrgPermissionIdentityActions,
|
OrgPermissionIdentityActions,
|
||||||
OrgPermissionKmipActions,
|
OrgPermissionKmipActions,
|
||||||
OrgPermissionMachineIdentityAuthTemplateActions,
|
OrgPermissionMachineIdentityAuthTemplateActions,
|
||||||
OrgPermissionSecretShareAction
|
OrgPermissionSecretShareAction,
|
||||||
|
OrgRelayPermissionActions
|
||||||
} from "@app/context/OrgPermissionContext/types";
|
} from "@app/context/OrgPermissionContext/types";
|
||||||
import { TPermission } from "@app/hooks/api/roles/types";
|
import { TPermission } from "@app/hooks/api/roles/types";
|
||||||
|
|
||||||
@@ -90,6 +91,15 @@ const orgGatewayPermissionSchema = z
|
|||||||
})
|
})
|
||||||
.optional();
|
.optional();
|
||||||
|
|
||||||
|
const orgRelayPermissionSchema = z
|
||||||
|
.object({
|
||||||
|
[OrgRelayPermissionActions.ListRelays]: z.boolean().optional(),
|
||||||
|
[OrgRelayPermissionActions.EditRelays]: z.boolean().optional(),
|
||||||
|
[OrgRelayPermissionActions.DeleteRelays]: z.boolean().optional(),
|
||||||
|
[OrgRelayPermissionActions.CreateRelays]: z.boolean().optional()
|
||||||
|
})
|
||||||
|
.optional();
|
||||||
|
|
||||||
const machineIdentityAuthTemplatePermissionSchema = z
|
const machineIdentityAuthTemplatePermissionSchema = z
|
||||||
.object({
|
.object({
|
||||||
[OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates]: z.boolean().optional(),
|
[OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates]: z.boolean().optional(),
|
||||||
@@ -147,6 +157,7 @@ export const formSchema = z.object({
|
|||||||
"app-connections": appConnectionsPermissionSchema,
|
"app-connections": appConnectionsPermissionSchema,
|
||||||
kmip: kmipPermissionSchema,
|
kmip: kmipPermissionSchema,
|
||||||
gateway: orgGatewayPermissionSchema,
|
gateway: orgGatewayPermissionSchema,
|
||||||
|
relay: orgRelayPermissionSchema,
|
||||||
"machine-identity-auth-template": machineIdentityAuthTemplatePermissionSchema,
|
"machine-identity-auth-template": machineIdentityAuthTemplatePermissionSchema,
|
||||||
"secret-share": secretSharingPermissionSchema
|
"secret-share": secretSharingPermissionSchema
|
||||||
})
|
})
|
||||||
|
|||||||
+180
@@ -0,0 +1,180 @@
|
|||||||
|
import { useEffect, useMemo } from "react";
|
||||||
|
import { Control, Controller, UseFormSetValue, useWatch } from "react-hook-form";
|
||||||
|
import { faChevronDown, faChevronRight } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
|
import { createNotification } from "@app/components/notifications";
|
||||||
|
import { Checkbox, Select, SelectItem, Td, Tr } from "@app/components/v2";
|
||||||
|
import { OrgRelayPermissionActions } from "@app/context/OrgPermissionContext/types";
|
||||||
|
import { useToggle } from "@app/hooks";
|
||||||
|
|
||||||
|
import { TFormSchema } from "../OrgRoleModifySection.utils";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isEditable: boolean;
|
||||||
|
setValue: UseFormSetValue<TFormSchema>;
|
||||||
|
control: Control<TFormSchema>;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Permission {
|
||||||
|
NoAccess = "no-access",
|
||||||
|
ReadOnly = "read-only",
|
||||||
|
FullAccess = "full-access",
|
||||||
|
Custom = "custom"
|
||||||
|
}
|
||||||
|
|
||||||
|
const PERMISSION_ACTIONS = [
|
||||||
|
{ action: OrgRelayPermissionActions.ListRelays, label: "List Relays" },
|
||||||
|
{ action: OrgRelayPermissionActions.CreateRelays, label: "Create Relays" },
|
||||||
|
{ action: OrgRelayPermissionActions.EditRelays, label: "Edit Relays" },
|
||||||
|
{ action: OrgRelayPermissionActions.DeleteRelays, label: "Delete Relays" }
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export const OrgRelayPermissionRow = ({ isEditable, control, setValue }: Props) => {
|
||||||
|
const [isRowExpanded, setIsRowExpanded] = useToggle();
|
||||||
|
const [isCustom, setIsCustom] = useToggle();
|
||||||
|
|
||||||
|
const rule = useWatch({
|
||||||
|
control,
|
||||||
|
name: "permissions.relay"
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedPermissionCategory = useMemo(() => {
|
||||||
|
const actions = Object.keys(rule || {}) as Array<keyof typeof rule>;
|
||||||
|
const totalActions = PERMISSION_ACTIONS.length;
|
||||||
|
const score = actions.map((key) => (rule?.[key] ? 1 : 0)).reduce((a, b) => a + b, 0 as number);
|
||||||
|
|
||||||
|
if (isCustom) return Permission.Custom;
|
||||||
|
if (score === 0) return Permission.NoAccess;
|
||||||
|
if (score === totalActions) return Permission.FullAccess;
|
||||||
|
if (score === 1 && rule?.[OrgRelayPermissionActions.ListRelays]) return Permission.ReadOnly;
|
||||||
|
|
||||||
|
return Permission.Custom;
|
||||||
|
}, [rule, isCustom]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedPermissionCategory === Permission.Custom) setIsCustom.on();
|
||||||
|
else setIsCustom.off();
|
||||||
|
}, [selectedPermissionCategory]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const isRowCustom = selectedPermissionCategory === Permission.Custom;
|
||||||
|
if (isRowCustom) {
|
||||||
|
setIsRowExpanded.on();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handlePermissionChange = (val: Permission) => {
|
||||||
|
if (!val) return;
|
||||||
|
if (val === Permission.Custom) {
|
||||||
|
setIsRowExpanded.on();
|
||||||
|
setIsCustom.on();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsCustom.off();
|
||||||
|
|
||||||
|
switch (val) {
|
||||||
|
case Permission.FullAccess:
|
||||||
|
setValue(
|
||||||
|
"permissions.relay",
|
||||||
|
{
|
||||||
|
[OrgRelayPermissionActions.ListRelays]: true,
|
||||||
|
[OrgRelayPermissionActions.EditRelays]: true,
|
||||||
|
[OrgRelayPermissionActions.CreateRelays]: true,
|
||||||
|
[OrgRelayPermissionActions.DeleteRelays]: true
|
||||||
|
},
|
||||||
|
{ shouldDirty: true }
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case Permission.ReadOnly:
|
||||||
|
setValue(
|
||||||
|
"permissions.relay",
|
||||||
|
{
|
||||||
|
[OrgRelayPermissionActions.ListRelays]: true,
|
||||||
|
[OrgRelayPermissionActions.EditRelays]: false,
|
||||||
|
[OrgRelayPermissionActions.CreateRelays]: false,
|
||||||
|
[OrgRelayPermissionActions.DeleteRelays]: false
|
||||||
|
},
|
||||||
|
{ shouldDirty: true }
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Permission.NoAccess:
|
||||||
|
default:
|
||||||
|
setValue(
|
||||||
|
"permissions.relay",
|
||||||
|
{
|
||||||
|
[OrgRelayPermissionActions.ListRelays]: false,
|
||||||
|
[OrgRelayPermissionActions.EditRelays]: false,
|
||||||
|
[OrgRelayPermissionActions.CreateRelays]: false,
|
||||||
|
[OrgRelayPermissionActions.DeleteRelays]: false
|
||||||
|
},
|
||||||
|
{ shouldDirty: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Tr
|
||||||
|
className="h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
|
||||||
|
onClick={() => setIsRowExpanded.toggle()}
|
||||||
|
>
|
||||||
|
<Td className="w-4">
|
||||||
|
<FontAwesomeIcon className="w-4" icon={isRowExpanded ? faChevronDown : faChevronRight} />
|
||||||
|
</Td>
|
||||||
|
<Td className="w-full select-none">Relays</Td>
|
||||||
|
<Td>
|
||||||
|
<Select
|
||||||
|
value={selectedPermissionCategory}
|
||||||
|
className="h-8 w-40 bg-mineshaft-700"
|
||||||
|
dropdownContainerClassName="border text-left border-mineshaft-600 bg-mineshaft-800"
|
||||||
|
onValueChange={handlePermissionChange}
|
||||||
|
isDisabled={!isEditable}
|
||||||
|
position="popper"
|
||||||
|
>
|
||||||
|
<SelectItem value={Permission.NoAccess}>No Access</SelectItem>
|
||||||
|
<SelectItem value={Permission.ReadOnly}>Read Only</SelectItem>
|
||||||
|
<SelectItem value={Permission.FullAccess}>Full Access</SelectItem>
|
||||||
|
<SelectItem value={Permission.Custom}>Custom</SelectItem>
|
||||||
|
</Select>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
{isRowExpanded && (
|
||||||
|
<Tr>
|
||||||
|
<Td colSpan={3} className="border-mineshaft-500 bg-mineshaft-900 p-8">
|
||||||
|
<div className="flex flex-grow flex-wrap justify-start gap-x-8 gap-y-4">
|
||||||
|
{PERMISSION_ACTIONS.map(({ action, label }) => {
|
||||||
|
return (
|
||||||
|
<Controller
|
||||||
|
name={`permissions.relay.${action}`}
|
||||||
|
key={`permissions.relay.${action}`}
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => (
|
||||||
|
<Checkbox
|
||||||
|
isChecked={Boolean(field.value)}
|
||||||
|
onCheckedChange={(e) => {
|
||||||
|
if (!isEditable) {
|
||||||
|
createNotification({
|
||||||
|
type: "error",
|
||||||
|
text: "Failed to update default role"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
field.onChange(e);
|
||||||
|
}}
|
||||||
|
id={`permissions.relay.${action}`}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Checkbox>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
+1
@@ -69,6 +69,7 @@ type Props = {
|
|||||||
| "organization-admin-console"
|
| "organization-admin-console"
|
||||||
| "kmip"
|
| "kmip"
|
||||||
| "gateway"
|
| "gateway"
|
||||||
|
| "relay"
|
||||||
| "secret-share"
|
| "secret-share"
|
||||||
| "billing"
|
| "billing"
|
||||||
| "audit-logs"
|
| "audit-logs"
|
||||||
|
|||||||
+6
@@ -23,6 +23,7 @@ import { OrgPermissionGroupRow } from "./OrgPermissionGroupRow";
|
|||||||
import { OrgPermissionIdentityRow } from "./OrgPermissionIdentityRow";
|
import { OrgPermissionIdentityRow } from "./OrgPermissionIdentityRow";
|
||||||
import { OrgPermissionKmipRow } from "./OrgPermissionKmipRow";
|
import { OrgPermissionKmipRow } from "./OrgPermissionKmipRow";
|
||||||
import { OrgPermissionMachineIdentityAuthTemplateRow } from "./OrgPermissionMachineIdentityAuthTemplateRow";
|
import { OrgPermissionMachineIdentityAuthTemplateRow } from "./OrgPermissionMachineIdentityAuthTemplateRow";
|
||||||
|
import { OrgRelayPermissionRow } from "./OrgPermissionRelayRow";
|
||||||
import { OrgPermissionSecretShareRow } from "./OrgPermissionSecretShareRow";
|
import { OrgPermissionSecretShareRow } from "./OrgPermissionSecretShareRow";
|
||||||
import { OrgRoleWorkspaceRow } from "./OrgRoleWorkspaceRow";
|
import { OrgRoleWorkspaceRow } from "./OrgRoleWorkspaceRow";
|
||||||
import { RolePermissionRow } from "./RolePermissionRow";
|
import { RolePermissionRow } from "./RolePermissionRow";
|
||||||
@@ -188,6 +189,11 @@ export const RolePermissionsSection = ({ roleId }: Props) => {
|
|||||||
setValue={setValue}
|
setValue={setValue}
|
||||||
isEditable={isCustomRole}
|
isEditable={isCustomRole}
|
||||||
/>
|
/>
|
||||||
|
<OrgRelayPermissionRow
|
||||||
|
control={control}
|
||||||
|
setValue={setValue}
|
||||||
|
isEditable={isCustomRole}
|
||||||
|
/>
|
||||||
<OrgPermissionBillingRow
|
<OrgPermissionBillingRow
|
||||||
control={control}
|
control={control}
|
||||||
setValue={setValue}
|
setValue={setValue}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ import { Route as organizationIdentityDetailsByIDPageRouteImport } from './pages
|
|||||||
import { Route as organizationGroupDetailsByIDPageRouteImport } from './pages/organization/GroupDetailsByIDPage/route'
|
import { Route as organizationGroupDetailsByIDPageRouteImport } from './pages/organization/GroupDetailsByIDPage/route'
|
||||||
import { Route as organizationSettingsPageRouteImport } from './pages/organization/SettingsPage/route'
|
import { Route as organizationSettingsPageRouteImport } from './pages/organization/SettingsPage/route'
|
||||||
import { Route as organizationSecretSharingPageRouteImport } from './pages/organization/SecretSharingPage/route'
|
import { Route as organizationSecretSharingPageRouteImport } from './pages/organization/SecretSharingPage/route'
|
||||||
|
import { Route as organizationGatewaysRelayRelayListPageRouteImport } from './pages/organization/Gateways/Relay/RelayListPage/route'
|
||||||
import { Route as organizationGatewaysGatewayListPageRouteImport } from './pages/organization/Gateways/GatewayListPage/route'
|
import { Route as organizationGatewaysGatewayListPageRouteImport } from './pages/organization/Gateways/GatewayListPage/route'
|
||||||
import { Route as organizationAppConnectionsAppConnectionsPageRouteImport } from './pages/organization/AppConnections/AppConnectionsPage/route'
|
import { Route as organizationAppConnectionsAppConnectionsPageRouteImport } from './pages/organization/AppConnections/AppConnectionsPage/route'
|
||||||
import { Route as sshLayoutImport } from './pages/ssh/layout'
|
import { Route as sshLayoutImport } from './pages/ssh/layout'
|
||||||
@@ -255,6 +256,10 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingImport =
|
|||||||
createFileRoute(
|
createFileRoute(
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing',
|
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing',
|
||||||
)()
|
)()
|
||||||
|
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysImport =
|
||||||
|
createFileRoute(
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/relays',
|
||||||
|
)()
|
||||||
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport =
|
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport =
|
||||||
createFileRoute(
|
createFileRoute(
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/gateways',
|
'/_authenticate/_inject-org-details/_org-layout/organization/gateways',
|
||||||
@@ -559,6 +564,14 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute =
|
|||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRoute =
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysImport.update({
|
||||||
|
id: '/relays',
|
||||||
|
path: '/relays',
|
||||||
|
getParentRoute: () =>
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute =
|
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute =
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport.update({
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport.update({
|
||||||
id: '/gateways',
|
id: '/gateways',
|
||||||
@@ -765,6 +778,14 @@ const organizationSecretSharingPageRouteRoute =
|
|||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute,
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const organizationGatewaysRelayRelayListPageRouteRoute =
|
||||||
|
organizationGatewaysRelayRelayListPageRouteImport.update({
|
||||||
|
id: '/',
|
||||||
|
path: '/',
|
||||||
|
getParentRoute: () =>
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
const organizationGatewaysGatewayListPageRouteRoute =
|
const organizationGatewaysGatewayListPageRouteRoute =
|
||||||
organizationGatewaysGatewayListPageRouteImport.update({
|
organizationGatewaysGatewayListPageRouteImport.update({
|
||||||
id: '/',
|
id: '/',
|
||||||
@@ -2376,6 +2397,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport
|
preLoaderRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport
|
||||||
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||||
}
|
}
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/relays': {
|
||||||
|
id: '/_authenticate/_inject-org-details/_org-layout/organization/relays'
|
||||||
|
path: '/relays'
|
||||||
|
fullPath: '/organization/relays'
|
||||||
|
preLoaderRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysImport
|
||||||
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||||
|
}
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing': {
|
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing': {
|
||||||
id: '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing'
|
id: '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing'
|
||||||
path: '/secret-sharing'
|
path: '/secret-sharing'
|
||||||
@@ -2411,6 +2439,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof organizationGatewaysGatewayListPageRouteImport
|
preLoaderRoute: typeof organizationGatewaysGatewayListPageRouteImport
|
||||||
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport
|
||||||
}
|
}
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/relays/': {
|
||||||
|
id: '/_authenticate/_inject-org-details/_org-layout/organization/relays/'
|
||||||
|
path: '/'
|
||||||
|
fullPath: '/organization/relays/'
|
||||||
|
preLoaderRoute: typeof organizationGatewaysRelayRelayListPageRouteImport
|
||||||
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysImport
|
||||||
|
}
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/': {
|
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/': {
|
||||||
id: '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/'
|
id: '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/'
|
||||||
path: '/'
|
path: '/'
|
||||||
@@ -3734,6 +3769,21 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
|
|||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteChildren,
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteChildren,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRouteChildren {
|
||||||
|
organizationGatewaysRelayRelayListPageRouteRoute: typeof organizationGatewaysRelayRelayListPageRouteRoute
|
||||||
|
}
|
||||||
|
|
||||||
|
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRouteChildren: AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRouteChildren =
|
||||||
|
{
|
||||||
|
organizationGatewaysRelayRelayListPageRouteRoute:
|
||||||
|
organizationGatewaysRelayRelayListPageRouteRoute,
|
||||||
|
}
|
||||||
|
|
||||||
|
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRouteWithChildren =
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRoute._addFileChildren(
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRouteChildren,
|
||||||
|
)
|
||||||
|
|
||||||
interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteChildren {
|
interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteChildren {
|
||||||
organizationSecretSharingPageRouteRoute: typeof organizationSecretSharingPageRouteRoute
|
organizationSecretSharingPageRouteRoute: typeof organizationSecretSharingPageRouteRoute
|
||||||
organizationSecretSharingSettingsPageRouteRoute: typeof organizationSecretSharingSettingsPageRouteRoute
|
organizationSecretSharingSettingsPageRouteRoute: typeof organizationSecretSharingSettingsPageRouteRoute
|
||||||
@@ -3776,6 +3826,7 @@ interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren {
|
|||||||
organizationProjectsPageRouteRoute: typeof organizationProjectsPageRouteRoute
|
organizationProjectsPageRouteRoute: typeof organizationProjectsPageRouteRoute
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRouteWithChildren
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren
|
||||||
organizationGroupDetailsByIDPageRouteRoute: typeof organizationGroupDetailsByIDPageRouteRoute
|
organizationGroupDetailsByIDPageRouteRoute: typeof organizationGroupDetailsByIDPageRouteRoute
|
||||||
@@ -3795,6 +3846,8 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren: Authentica
|
|||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren,
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren,
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute:
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute:
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren,
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren,
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRoute:
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRouteWithChildren,
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute:
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute:
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren,
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren,
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRoute:
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRoute:
|
||||||
@@ -4694,11 +4747,13 @@ export interface FileRoutesByFullPath {
|
|||||||
'/admin/integrations': typeof adminIntegrationsPageRouteRoute
|
'/admin/integrations': typeof adminIntegrationsPageRouteRoute
|
||||||
'/organization/app-connections': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
|
'/organization/app-connections': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
|
||||||
'/organization/gateways': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
|
'/organization/gateways': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
|
||||||
|
'/organization/relays': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRouteWithChildren
|
||||||
'/organization/secret-sharing': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren
|
'/organization/secret-sharing': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren
|
||||||
'/organization/settings': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren
|
'/organization/settings': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren
|
||||||
'/secret-manager/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdRouteWithChildren
|
'/secret-manager/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdRouteWithChildren
|
||||||
'/organization/app-connections/': typeof organizationAppConnectionsAppConnectionsPageRouteRoute
|
'/organization/app-connections/': typeof organizationAppConnectionsAppConnectionsPageRouteRoute
|
||||||
'/organization/gateways/': typeof organizationGatewaysGatewayListPageRouteRoute
|
'/organization/gateways/': typeof organizationGatewaysGatewayListPageRouteRoute
|
||||||
|
'/organization/relays/': typeof organizationGatewaysRelayRelayListPageRouteRoute
|
||||||
'/organization/secret-sharing/': typeof organizationSecretSharingPageRouteRoute
|
'/organization/secret-sharing/': typeof organizationSecretSharingPageRouteRoute
|
||||||
'/organization/settings/': typeof organizationSettingsPageRouteRoute
|
'/organization/settings/': typeof organizationSettingsPageRouteRoute
|
||||||
'/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
'/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
||||||
@@ -4915,6 +4970,7 @@ export interface FileRoutesByTo {
|
|||||||
'/secret-manager/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdRouteWithChildren
|
'/secret-manager/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdRouteWithChildren
|
||||||
'/organization/app-connections': typeof organizationAppConnectionsAppConnectionsPageRouteRoute
|
'/organization/app-connections': typeof organizationAppConnectionsAppConnectionsPageRouteRoute
|
||||||
'/organization/gateways': typeof organizationGatewaysGatewayListPageRouteRoute
|
'/organization/gateways': typeof organizationGatewaysGatewayListPageRouteRoute
|
||||||
|
'/organization/relays': typeof organizationGatewaysRelayRelayListPageRouteRoute
|
||||||
'/organization/secret-sharing': typeof organizationSecretSharingPageRouteRoute
|
'/organization/secret-sharing': typeof organizationSecretSharingPageRouteRoute
|
||||||
'/organization/settings': typeof organizationSettingsPageRouteRoute
|
'/organization/settings': typeof organizationSettingsPageRouteRoute
|
||||||
'/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
'/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
||||||
@@ -5134,11 +5190,13 @@ export interface FileRoutesById {
|
|||||||
'/_authenticate/_inject-org-details/admin/_admin-layout/integrations': typeof adminIntegrationsPageRouteRoute
|
'/_authenticate/_inject-org-details/admin/_admin-layout/integrations': typeof adminIntegrationsPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/app-connections': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
|
'/_authenticate/_inject-org-details/_org-layout/organization/app-connections': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/gateways': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
|
'/_authenticate/_inject-org-details/_org-layout/organization/gateways': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/relays': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationRelaysRouteWithChildren
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren
|
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/settings': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren
|
'/_authenticate/_inject-org-details/_org-layout/organization/settings': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren
|
||||||
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdRouteWithChildren
|
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdRouteWithChildren
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/app-connections/': typeof organizationAppConnectionsAppConnectionsPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/app-connections/': typeof organizationAppConnectionsAppConnectionsPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/gateways/': typeof organizationGatewaysGatewayListPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/gateways/': typeof organizationGatewaysGatewayListPageRouteRoute
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/relays/': typeof organizationGatewaysRelayRelayListPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/': typeof organizationSecretSharingPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/': typeof organizationSecretSharingPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/settings/': typeof organizationSettingsPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/settings/': typeof organizationSettingsPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
||||||
@@ -5365,11 +5423,13 @@ export interface FileRouteTypes {
|
|||||||
| '/admin/integrations'
|
| '/admin/integrations'
|
||||||
| '/organization/app-connections'
|
| '/organization/app-connections'
|
||||||
| '/organization/gateways'
|
| '/organization/gateways'
|
||||||
|
| '/organization/relays'
|
||||||
| '/organization/secret-sharing'
|
| '/organization/secret-sharing'
|
||||||
| '/organization/settings'
|
| '/organization/settings'
|
||||||
| '/secret-manager/$projectId'
|
| '/secret-manager/$projectId'
|
||||||
| '/organization/app-connections/'
|
| '/organization/app-connections/'
|
||||||
| '/organization/gateways/'
|
| '/organization/gateways/'
|
||||||
|
| '/organization/relays/'
|
||||||
| '/organization/secret-sharing/'
|
| '/organization/secret-sharing/'
|
||||||
| '/organization/settings/'
|
| '/organization/settings/'
|
||||||
| '/organization/groups/$groupId'
|
| '/organization/groups/$groupId'
|
||||||
@@ -5585,6 +5645,7 @@ export interface FileRouteTypes {
|
|||||||
| '/secret-manager/$projectId'
|
| '/secret-manager/$projectId'
|
||||||
| '/organization/app-connections'
|
| '/organization/app-connections'
|
||||||
| '/organization/gateways'
|
| '/organization/gateways'
|
||||||
|
| '/organization/relays'
|
||||||
| '/organization/secret-sharing'
|
| '/organization/secret-sharing'
|
||||||
| '/organization/settings'
|
| '/organization/settings'
|
||||||
| '/organization/groups/$groupId'
|
| '/organization/groups/$groupId'
|
||||||
@@ -5802,11 +5863,13 @@ export interface FileRouteTypes {
|
|||||||
| '/_authenticate/_inject-org-details/admin/_admin-layout/integrations'
|
| '/_authenticate/_inject-org-details/admin/_admin-layout/integrations'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/app-connections'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/app-connections'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/gateways'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/gateways'
|
||||||
|
| '/_authenticate/_inject-org-details/_org-layout/organization/relays'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/settings'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/settings'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId'
|
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/app-connections/'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/app-connections/'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/gateways/'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/gateways/'
|
||||||
|
| '/_authenticate/_inject-org-details/_org-layout/organization/relays/'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/settings/'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/settings/'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId'
|
||||||
@@ -6228,6 +6291,7 @@ export const routeTree = rootRoute
|
|||||||
"/_authenticate/_inject-org-details/_org-layout/organization/projects",
|
"/_authenticate/_inject-org-details/_org-layout/organization/projects",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/app-connections",
|
"/_authenticate/_inject-org-details/_org-layout/organization/app-connections",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/gateways",
|
"/_authenticate/_inject-org-details/_org-layout/organization/gateways",
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/relays",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing",
|
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/settings",
|
"/_authenticate/_inject-org-details/_org-layout/organization/settings",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId",
|
"/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId",
|
||||||
@@ -6309,6 +6373,13 @@ export const routeTree = rootRoute
|
|||||||
"/_authenticate/_inject-org-details/_org-layout/organization/gateways/"
|
"/_authenticate/_inject-org-details/_org-layout/organization/gateways/"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/relays": {
|
||||||
|
"filePath": "",
|
||||||
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization",
|
||||||
|
"children": [
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/relays/"
|
||||||
|
]
|
||||||
|
},
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing": {
|
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing": {
|
||||||
"filePath": "",
|
"filePath": "",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization",
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization",
|
||||||
@@ -6340,6 +6411,10 @@ export const routeTree = rootRoute
|
|||||||
"filePath": "organization/Gateways/GatewayListPage/route.tsx",
|
"filePath": "organization/Gateways/GatewayListPage/route.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization/gateways"
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization/gateways"
|
||||||
},
|
},
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/relays/": {
|
||||||
|
"filePath": "organization/Gateways/Relay/RelayListPage/route.tsx",
|
||||||
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization/relays"
|
||||||
|
},
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/": {
|
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/": {
|
||||||
"filePath": "organization/SecretSharingPage/route.tsx",
|
"filePath": "organization/SecretSharingPage/route.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing"
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing"
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ const organizationRoutes = route("/organization", [
|
|||||||
"organization/AppConnections/OauthCallbackPage/route.tsx"
|
"organization/AppConnections/OauthCallbackPage/route.tsx"
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
route("/gateways", [index("organization/Gateways/GatewayListPage/route.tsx")])
|
route("/gateways", [index("organization/Gateways/GatewayListPage/route.tsx")]),
|
||||||
|
route("/relays", [index("organization/Gateways/Relay/RelayListPage/route.tsx")])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const secretManagerRoutes = route("/projects/secret-management/$projectId", [
|
const secretManagerRoutes = route("/projects/secret-management/$projectId", [
|
||||||
|
|||||||
Reference in New Issue
Block a user