diff --git a/dashboard/drizzle/relations.ts b/dashboard/drizzle/relations.ts index 615b353..47aff7f 100644 --- a/dashboard/drizzle/relations.ts +++ b/dashboard/drizzle/relations.ts @@ -1,334 +1,334 @@ import { relations } from 'drizzle-orm/relations'; import { - continuityContainers, - courierMessageDispatches, - courierMessages, + continuity_containers, + courier_message_dispatches, + courier_messages, identities, - identityCredentialIdentifiers, - identityCredentials, - identityCredentialTypes, - identityLoginCodes, - identityRecoveryAddresses, - identityRecoveryCodes, - identityRecoveryTokens, - identityRegistrationCodes, - identityVerifiableAddresses, - identityVerificationCodes, - identityVerificationTokens, + identity_credential_identifiers, + identity_credential_types, + identity_credentials, + identity_login_codes, + identity_recovery_addresses, + identity_recovery_codes, + identity_recovery_tokens, + identity_registration_codes, + identity_verifiable_addresses, + identity_verification_codes, + identity_verification_tokens, networks, - selfserviceErrors, - selfserviceLoginFlows, - selfserviceRecoveryFlows, - selfserviceRegistrationFlows, - selfserviceSettingsFlows, - selfserviceVerificationFlows, - sessionDevices, + selfservice_errors, + selfservice_login_flows, + selfservice_recovery_flows, + selfservice_registration_flows, + selfservice_settings_flows, + selfservice_verification_flows, + session_devices, sessions, } from './schema'; -export const identityCredentialsRelations = relations(identityCredentials, ({ one, many }) => ({ +export const identityCredentialsRelations = relations(identity_credentials, ({ one, many }) => ({ identity: one(identities, { - fields: [identityCredentials.identityId], + fields: [identity_credentials.identity_id], references: [identities.id], }), - identityCredentialType: one(identityCredentialTypes, { - fields: [identityCredentials.identityCredentialTypeId], - references: [identityCredentialTypes.id], + identityCredentialType: one(identity_credential_types, { + fields: [identity_credentials.identity_credential_type_id], + references: [identity_credential_types.id], }), network: one(networks, { - fields: [identityCredentials.nid], + fields: [identity_credentials.nid], references: [networks.id], }), - identityCredentialIdentifiers: many(identityCredentialIdentifiers), + identityCredentialIdentifiers: many(identity_credential_identifiers), })); export const identitiesRelations = relations(identities, ({ one, many }) => ({ - identityCredentials: many(identityCredentials), + identityCredentials: many(identity_credentials), network: one(networks, { fields: [identities.nid], references: [networks.id], }), - identityVerifiableAddresses: many(identityVerifiableAddresses), - selfserviceSettingsFlows: many(selfserviceSettingsFlows), - continuityContainers: many(continuityContainers), + identityVerifiableAddresses: many(identity_verifiable_addresses), + selfserviceSettingsFlows: many(selfservice_settings_flows), + continuityContainers: many(continuity_containers), sessions: many(sessions), - identityRecoveryAddresses: many(identityRecoveryAddresses), - selfserviceRecoveryFlows: many(selfserviceRecoveryFlows), - identityRecoveryTokens: many(identityRecoveryTokens), - identityRecoveryCodes: many(identityRecoveryCodes), - identityLoginCodes: many(identityLoginCodes), + identityRecoveryAddresses: many(identity_recovery_addresses), + selfserviceRecoveryFlows: many(selfservice_recovery_flows), + identityRecoveryTokens: many(identity_recovery_tokens), + identityRecoveryCodes: many(identity_recovery_codes), + identityLoginCodes: many(identity_login_codes), })); -export const identityCredentialTypesRelations = relations(identityCredentialTypes, ({ many }) => ({ - identityCredentials: many(identityCredentials), - identityCredentialIdentifiers: many(identityCredentialIdentifiers), +export const identityCredentialTypesRelations = relations(identity_credential_types, ({ many }) => ({ + identityCredentials: many(identity_credentials), + identityCredentialIdentifiers: many(identity_credential_identifiers), })); export const networksRelations = relations(networks, ({ many }) => ({ - identityCredentials: many(identityCredentials), - selfserviceLoginFlows: many(selfserviceLoginFlows), - selfserviceRegistrationFlows: many(selfserviceRegistrationFlows), + identityCredentials: many(identity_credentials), + selfserviceLoginFlows: many(selfservice_login_flows), + selfserviceRegistrationFlows: many(selfservice_registration_flows), identities: many(identities), - identityCredentialIdentifiers: many(identityCredentialIdentifiers), - identityVerifiableAddresses: many(identityVerifiableAddresses), - courierMessages: many(courierMessages), - selfserviceErrors: many(selfserviceErrors), - selfserviceVerificationFlows: many(selfserviceVerificationFlows), - selfserviceSettingsFlows: many(selfserviceSettingsFlows), - continuityContainers: many(continuityContainers), + identityCredentialIdentifiers: many(identity_credential_identifiers), + identityVerifiableAddresses: many(identity_verifiable_addresses), + courierMessages: many(courier_messages), + selfserviceErrors: many(selfservice_errors), + selfserviceVerificationFlows: many(selfservice_verification_flows), + selfserviceSettingsFlows: many(selfservice_settings_flows), + continuityContainers: many(continuity_containers), sessions: many(sessions), - identityRecoveryAddresses: many(identityRecoveryAddresses), - identityVerificationTokens: many(identityVerificationTokens), - selfserviceRecoveryFlows: many(selfserviceRecoveryFlows), - identityRecoveryTokens: many(identityRecoveryTokens), - identityRecoveryCodes: many(identityRecoveryCodes), - sessionDevices: many(sessionDevices), - identityVerificationCodes: many(identityVerificationCodes), - courierMessageDispatches: many(courierMessageDispatches), - identityLoginCodes: many(identityLoginCodes), - identityRegistrationCodes: many(identityRegistrationCodes), + identityRecoveryAddresses: many(identity_recovery_addresses), + identityVerificationTokens: many(identity_verification_tokens), + selfserviceRecoveryFlows: many(selfservice_recovery_flows), + identityRecoveryTokens: many(identity_recovery_tokens), + identityRecoveryCodes: many(identity_recovery_codes), + sessionDevices: many(session_devices), + identityVerificationCodes: many(identity_verification_codes), + courierMessageDispatches: many(courier_message_dispatches), + identityLoginCodes: many(identity_login_codes), + identityRegistrationCodes: many(identity_registration_codes), })); -export const selfserviceLoginFlowsRelations = relations(selfserviceLoginFlows, ({ one, many }) => ({ +export const selfserviceLoginFlowsRelations = relations(selfservice_login_flows, ({ one, many }) => ({ network: one(networks, { - fields: [selfserviceLoginFlows.nid], + fields: [selfservice_login_flows.nid], references: [networks.id], }), - identityLoginCodes: many(identityLoginCodes), + identityLoginCodes: many(identity_login_codes), })); -export const selfserviceRegistrationFlowsRelations = relations(selfserviceRegistrationFlows, ({ one, many }) => ({ +export const selfserviceRegistrationFlowsRelations = relations(selfservice_registration_flows, ({ one, many }) => ({ network: one(networks, { - fields: [selfserviceRegistrationFlows.nid], + fields: [selfservice_registration_flows.nid], references: [networks.id], }), - identityRegistrationCodes: many(identityRegistrationCodes), + identityRegistrationCodes: many(identity_registration_codes), })); -export const identityCredentialIdentifiersRelations = relations(identityCredentialIdentifiers, ({ one }) => ({ - identityCredential: one(identityCredentials, { - fields: [identityCredentialIdentifiers.identityCredentialId], - references: [identityCredentials.id], +export const identityCredentialIdentifiersRelations = relations(identity_credential_identifiers, ({ one }) => ({ + identityCredential: one(identity_credentials, { + fields: [identity_credential_identifiers.identity_credential_id], + references: [identity_credentials.id], }), network: one(networks, { - fields: [identityCredentialIdentifiers.nid], + fields: [identity_credential_identifiers.nid], references: [networks.id], }), - identityCredentialType: one(identityCredentialTypes, { - fields: [identityCredentialIdentifiers.identityCredentialTypeId], - references: [identityCredentialTypes.id], + identityCredentialType: one(identity_credential_types, { + fields: [identity_credential_identifiers.identity_credential_type_id], + references: [identity_credential_types.id], }), })); -export const identityVerifiableAddressesRelations = relations(identityVerifiableAddresses, ({ one, many }) => ({ +export const identityVerifiableAddressesRelations = relations(identity_verifiable_addresses, ({ one, many }) => ({ identity: one(identities, { - fields: [identityVerifiableAddresses.identityId], + fields: [identity_verifiable_addresses.identity_id], references: [identities.id], }), network: one(networks, { - fields: [identityVerifiableAddresses.nid], + fields: [identity_verifiable_addresses.nid], references: [networks.id], }), - identityVerificationTokens: many(identityVerificationTokens), - identityVerificationCodes: many(identityVerificationCodes), + identityVerificationTokens: many(identity_verification_tokens), + identityVerificationCodes: many(identity_verification_codes), })); -export const courierMessagesRelations = relations(courierMessages, ({ one, many }) => ({ +export const courierMessagesRelations = relations(courier_messages, ({ one, many }) => ({ network: one(networks, { - fields: [courierMessages.nid], + fields: [courier_messages.nid], references: [networks.id], }), - courierMessageDispatches: many(courierMessageDispatches), + courierMessageDispatches: many(courier_message_dispatches), })); -export const selfserviceErrorsRelations = relations(selfserviceErrors, ({ one }) => ({ +export const selfserviceErrorsRelations = relations(selfservice_errors, ({ one }) => ({ network: one(networks, { - fields: [selfserviceErrors.nid], + fields: [selfservice_errors.nid], references: [networks.id], }), })); -export const selfserviceVerificationFlowsRelations = relations(selfserviceVerificationFlows, ({ one, many }) => ({ +export const selfserviceVerificationFlowsRelations = relations(selfservice_verification_flows, ({ one, many }) => ({ network: one(networks, { - fields: [selfserviceVerificationFlows.nid], + fields: [selfservice_verification_flows.nid], references: [networks.id], }), - identityVerificationTokens: many(identityVerificationTokens), - identityVerificationCodes: many(identityVerificationCodes), + identityVerificationTokens: many(identity_verification_tokens), + identityVerificationCodes: many(identity_verification_codes), })); -export const selfserviceSettingsFlowsRelations = relations(selfserviceSettingsFlows, ({ one }) => ({ +export const selfserviceSettingsFlowsRelations = relations(selfservice_settings_flows, ({ one }) => ({ identity: one(identities, { - fields: [selfserviceSettingsFlows.identityId], + fields: [selfservice_settings_flows.identity_id], references: [identities.id], }), network: one(networks, { - fields: [selfserviceSettingsFlows.nid], + fields: [selfservice_settings_flows.nid], references: [networks.id], }), })); -export const continuityContainersRelations = relations(continuityContainers, ({ one }) => ({ +export const continuityContainersRelations = relations(continuity_containers, ({ one }) => ({ identity: one(identities, { - fields: [continuityContainers.identityId], + fields: [continuity_containers.identity_id], references: [identities.id], }), network: one(networks, { - fields: [continuityContainers.nid], + fields: [continuity_containers.nid], references: [networks.id], }), })); export const sessionsRelations = relations(sessions, ({ one, many }) => ({ identity: one(identities, { - fields: [sessions.identityId], + fields: [sessions.identity_id], references: [identities.id], }), network: one(networks, { fields: [sessions.nid], references: [networks.id], }), - sessionDevices: many(sessionDevices), + sessionDevices: many(session_devices), })); -export const identityRecoveryAddressesRelations = relations(identityRecoveryAddresses, ({ one, many }) => ({ +export const identityRecoveryAddressesRelations = relations(identity_recovery_addresses, ({ one, many }) => ({ identity: one(identities, { - fields: [identityRecoveryAddresses.identityId], + fields: [identity_recovery_addresses.identity_id], references: [identities.id], }), network: one(networks, { - fields: [identityRecoveryAddresses.nid], + fields: [identity_recovery_addresses.nid], references: [networks.id], }), - identityRecoveryTokens: many(identityRecoveryTokens), - identityRecoveryCodes: many(identityRecoveryCodes), + identityRecoveryTokens: many(identity_recovery_tokens), + identityRecoveryCodes: many(identity_recovery_codes), })); -export const identityVerificationTokensRelations = relations(identityVerificationTokens, ({ one }) => ({ - identityVerifiableAddress: one(identityVerifiableAddresses, { - fields: [identityVerificationTokens.identityVerifiableAddressId], - references: [identityVerifiableAddresses.id], +export const identityVerificationTokensRelations = relations(identity_verification_tokens, ({ one }) => ({ + identityVerifiableAddress: one(identity_verifiable_addresses, { + fields: [identity_verification_tokens.identity_verifiable_address_id], + references: [identity_verifiable_addresses.id], }), - selfserviceVerificationFlow: one(selfserviceVerificationFlows, { - fields: [identityVerificationTokens.selfserviceVerificationFlowId], - references: [selfserviceVerificationFlows.id], + selfserviceVerificationFlow: one(selfservice_verification_flows, { + fields: [identity_verification_tokens.selfservice_verification_flow_id], + references: [selfservice_verification_flows.id], }), network: one(networks, { - fields: [identityVerificationTokens.nid], + fields: [identity_verification_tokens.nid], references: [networks.id], }), })); -export const selfserviceRecoveryFlowsRelations = relations(selfserviceRecoveryFlows, ({ one, many }) => ({ +export const selfserviceRecoveryFlowsRelations = relations(selfservice_recovery_flows, ({ one, many }) => ({ identity: one(identities, { - fields: [selfserviceRecoveryFlows.recoveredIdentityId], + fields: [selfservice_recovery_flows.recovered_identity_id], references: [identities.id], }), network: one(networks, { - fields: [selfserviceRecoveryFlows.nid], + fields: [selfservice_recovery_flows.nid], references: [networks.id], }), - identityRecoveryTokens: many(identityRecoveryTokens), - identityRecoveryCodes: many(identityRecoveryCodes), + identityRecoveryTokens: many(identity_recovery_tokens), + identityRecoveryCodes: many(identity_recovery_codes), })); -export const identityRecoveryTokensRelations = relations(identityRecoveryTokens, ({ one }) => ({ - selfserviceRecoveryFlow: one(selfserviceRecoveryFlows, { - fields: [identityRecoveryTokens.selfserviceRecoveryFlowId], - references: [selfserviceRecoveryFlows.id], +export const identityRecoveryTokensRelations = relations(identity_recovery_tokens, ({ one }) => ({ + selfserviceRecoveryFlow: one(selfservice_recovery_flows, { + fields: [identity_recovery_tokens.selfservice_recovery_flow_id], + references: [selfservice_recovery_flows.id], }), network: one(networks, { - fields: [identityRecoveryTokens.nid], + fields: [identity_recovery_tokens.nid], references: [networks.id], }), - identityRecoveryAddress: one(identityRecoveryAddresses, { - fields: [identityRecoveryTokens.identityRecoveryAddressId], - references: [identityRecoveryAddresses.id], + identityRecoveryAddress: one(identity_recovery_addresses, { + fields: [identity_recovery_tokens.identity_recovery_address_id], + references: [identity_recovery_addresses.id], }), identity: one(identities, { - fields: [identityRecoveryTokens.identityId], + fields: [identity_recovery_tokens.identity_id], references: [identities.id], }), })); -export const identityRecoveryCodesRelations = relations(identityRecoveryCodes, ({ one }) => ({ - identityRecoveryAddress: one(identityRecoveryAddresses, { - fields: [identityRecoveryCodes.identityRecoveryAddressId], - references: [identityRecoveryAddresses.id], +export const identityRecoveryCodesRelations = relations(identity_recovery_codes, ({ one }) => ({ + identityRecoveryAddress: one(identity_recovery_addresses, { + fields: [identity_recovery_codes.identity_recovery_address_id], + references: [identity_recovery_addresses.id], }), - selfserviceRecoveryFlow: one(selfserviceRecoveryFlows, { - fields: [identityRecoveryCodes.selfserviceRecoveryFlowId], - references: [selfserviceRecoveryFlows.id], + selfserviceRecoveryFlow: one(selfservice_recovery_flows, { + fields: [identity_recovery_codes.selfservice_recovery_flow_id], + references: [selfservice_recovery_flows.id], }), identity: one(identities, { - fields: [identityRecoveryCodes.identityId], + fields: [identity_recovery_codes.identity_id], references: [identities.id], }), network: one(networks, { - fields: [identityRecoveryCodes.nid], + fields: [identity_recovery_codes.nid], references: [networks.id], }), })); -export const sessionDevicesRelations = relations(sessionDevices, ({ one }) => ({ +export const sessionDevicesRelations = relations(session_devices, ({ one }) => ({ session: one(sessions, { - fields: [sessionDevices.sessionId], + fields: [session_devices.session_id], references: [sessions.id], }), network: one(networks, { - fields: [sessionDevices.nid], + fields: [session_devices.nid], references: [networks.id], }), })); -export const identityVerificationCodesRelations = relations(identityVerificationCodes, ({ one }) => ({ - identityVerifiableAddress: one(identityVerifiableAddresses, { - fields: [identityVerificationCodes.identityVerifiableAddressId], - references: [identityVerifiableAddresses.id], +export const identityVerificationCodesRelations = relations(identity_verification_codes, ({ one }) => ({ + identityVerifiableAddress: one(identity_verifiable_addresses, { + fields: [identity_verification_codes.identity_verifiable_address_id], + references: [identity_verifiable_addresses.id], }), - selfserviceVerificationFlow: one(selfserviceVerificationFlows, { - fields: [identityVerificationCodes.selfserviceVerificationFlowId], - references: [selfserviceVerificationFlows.id], + selfserviceVerificationFlow: one(selfservice_verification_flows, { + fields: [identity_verification_codes.selfservice_verification_flow_id], + references: [selfservice_verification_flows.id], }), network: one(networks, { - fields: [identityVerificationCodes.nid], + fields: [identity_verification_codes.nid], references: [networks.id], }), })); -export const courierMessageDispatchesRelations = relations(courierMessageDispatches, ({ one }) => ({ - courierMessage: one(courierMessages, { - fields: [courierMessageDispatches.messageId], - references: [courierMessages.id], +export const courierMessageDispatchesRelations = relations(courier_message_dispatches, ({ one }) => ({ + courierMessage: one(courier_messages, { + fields: [courier_message_dispatches.message_id], + references: [courier_messages.id], }), network: one(networks, { - fields: [courierMessageDispatches.nid], + fields: [courier_message_dispatches.nid], references: [networks.id], }), })); -export const identityLoginCodesRelations = relations(identityLoginCodes, ({ one }) => ({ - selfserviceLoginFlow: one(selfserviceLoginFlows, { - fields: [identityLoginCodes.selfserviceLoginFlowId], - references: [selfserviceLoginFlows.id], +export const identityLoginCodesRelations = relations(identity_login_codes, ({ one }) => ({ + selfserviceLoginFlow: one(selfservice_login_flows, { + fields: [identity_login_codes.selfservice_login_flow_id], + references: [selfservice_login_flows.id], }), network: one(networks, { - fields: [identityLoginCodes.nid], + fields: [identity_login_codes.nid], references: [networks.id], }), identity: one(identities, { - fields: [identityLoginCodes.identityId], + fields: [identity_login_codes.identity_id], references: [identities.id], }), })); -export const identityRegistrationCodesRelations = relations(identityRegistrationCodes, ({ one }) => ({ - selfserviceRegistrationFlow: one(selfserviceRegistrationFlows, { - fields: [identityRegistrationCodes.selfserviceRegistrationFlowId], - references: [selfserviceRegistrationFlows.id], +export const identityRegistrationCodesRelations = relations(identity_registration_codes, ({ one }) => ({ + selfserviceRegistrationFlow: one(selfservice_registration_flows, { + fields: [identity_registration_codes.selfservice_registration_flow_id], + references: [selfservice_registration_flows.id], }), network: one(networks, { - fields: [identityRegistrationCodes.nid], + fields: [identity_registration_codes.nid], references: [networks.id], }), })); \ No newline at end of file diff --git a/dashboard/src/app/(inside)/page.tsx b/dashboard/src/app/(inside)/page.tsx index 604a7e2..607c2c4 100644 --- a/dashboard/src/app/(inside)/page.tsx +++ b/dashboard/src/app/(inside)/page.tsx @@ -1,40 +1,21 @@ -import { getHydraMetadataApi, getKetoMetadataApi, getKratosMetadataApi } from '@/ory/sdk/server'; -import { MetadataApiReady, StatusCard } from '@/components/status-card'; +import { StatusCard } from '@/components/status-card'; +import { hydraMetadata, ketoMetadata, kratosMetadata } from '@/lib/action/metadata'; +import { checkPermission, requirePermission, requireSession } from '@/lib/action/authentication'; +import InsufficientPermission from '@/components/insufficient-permission'; +import { permission, relation } from '@/lib/permission'; export default async function RootPage() { - const kratosMetadataApi = await getKratosMetadataApi(); - const kratosVersion = await kratosMetadataApi.getVersion() - .then(res => res.data.version) - .catch(() => undefined); - const kratosStatus = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/ready') - .then((response) => response.json() as MetadataApiReady) - .catch(() => { - return { errors: ['No instance running'] } as MetadataApiReady; - }); + const session = await requireSession(); + const identityId = session.identity!.id; + await requirePermission(permission.stack.dashboard, relation.access, identityId); - const hydraMetadataApi = await getHydraMetadataApi(); - const hydraVersion = await hydraMetadataApi.getVersion() - .then(res => res.data.version) - .catch(() => undefined); - const hydraStatus = await fetch(process.env.ORY_HYDRA_ADMIN_URL + '/health/ready') - .then((response) => response.json() as MetadataApiReady) - .catch(() => { - return { errors: ['No instance running'] } as MetadataApiReady; - }); - - - const ketoMetadataApi = await getKetoMetadataApi(); - const ketoVersion = await ketoMetadataApi.getVersion() - .then(res => res.data.version) - .catch(() => undefined); - const ketoStatus = await fetch(process.env.ORY_KETO_ADMIN_URL + '/health/ready') - .then((response) => response.json() as MetadataApiReady) - .catch(() => { - return { errors: ['No instance running'] } as MetadataApiReady; - }); + const pmAccessStackStatus = await checkPermission(permission.stack.status, relation.access, identityId); + const kratos = pmAccessStackStatus && await kratosMetadata(); + const hydra = pmAccessStackStatus && await hydraMetadata(); + const keto = pmAccessStackStatus && await ketoMetadata(); return (
@@ -43,25 +24,46 @@ export default async function RootPage() {

See the list of all applications in your stack

- - - -
+ { + !pmAccessStackStatus && ( + + ) + } + { + kratos && ( + + ) + } + { + hydra && ( + + ) + } + { + keto && ( + + ) + }
); diff --git a/dashboard/src/app/(inside)/user/[id]/page.tsx b/dashboard/src/app/(inside)/user/[id]/page.tsx index 83cc3b3..e132f18 100644 --- a/dashboard/src/app/(inside)/user/[id]/page.tsx +++ b/dashboard/src/app/(inside)/user/[id]/page.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { getIdentityApi } from '@/ory/sdk/server'; import { ErrorDisplay } from '@/components/error'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { IdentityTraits } from '@/components/identity/identity-traits'; @@ -11,6 +10,11 @@ import { Badge } from '@/components/ui/badge'; import { Check, X } from 'lucide-react'; import { IdentityActions } from '@/components/identity/identity-actions'; import { IdentityCredentials } from '@/components/identity/identity-credentials'; +import { checkPermission, requirePermission, requireSession } from '@/lib/action/authentication'; +import { permission, relation } from '@/lib/permission'; +import { redirect } from 'next/navigation'; +import InsufficientPermission from '@/components/insufficient-permission'; +import { getIdentity, getIdentitySchema, listIdentitySessions } from '@/lib/action/identity'; interface MergedAddress { recovery_id?: string; @@ -76,172 +80,229 @@ function mergeAddresses( export default async function UserDetailsPage({ params }: { params: Promise<{ id: string }> }) { - const identityId = (await params).id; + const session = await requireSession(); + const identityId = session.identity!.id; - const identityApi = await getIdentityApi(); - const identity = await identityApi.getIdentity({ id: identityId }) - .then((response) => { - console.log('identity', response.data); - return response.data; - }) - .catch(() => { - console.log('Identity not found'); - }); + await requirePermission(permission.stack.dashboard, relation.access, identityId); - const sessions = await identityApi.listIdentitySessions({ id: identityId }) - .then((response) => response.data) - .catch(() => { - console.log('No sessions found'); - }); - - if (!identity) { - return ; + const pmAccessUser = await checkPermission(permission.user.it, relation.access, identityId); + if (!pmAccessUser) { + return redirect('/user'); } - if (!identity.verifiable_addresses || !identity.verifiable_addresses[0]) { + const pmDeleteUser = await checkPermission(permission.user.it, relation.delete, identityId); + const pmAccessUserTrait = await checkPermission(permission.user.trait, relation.access, identityId); + const pmEditUserTraits = await checkPermission(permission.user.trait, relation.edit, identityId); + const pmAccessUserAddress = await checkPermission(permission.user.address, relation.access, identityId); + const pmAccessUserCredential = await checkPermission(permission.user.credential, relation.access, identityId); + const pmEditUserState = await checkPermission(permission.user.state, relation.edit, identityId); + const pmAccessUserSession = await checkPermission(permission.user.session, relation.access, identityId); + const pmDeleteUserSession = await checkPermission(permission.user.session, relation.delete, identityId); + const pmCreateUserCode = await checkPermission(permission.user.code, relation.create, identityId); + const pmCreateUserLink = await checkPermission(permission.user.link, relation.create, identityId); + + const detailIdentityId = (await params).id; + const detailIdentity = pmAccessUser && await getIdentity(detailIdentityId); + + if (!detailIdentity) { + return ; + } + + if (!detailIdentity.verifiable_addresses || !detailIdentity.verifiable_addresses[0]) { return ; } - const identitySchema = await identityApi - .getIdentitySchema({ id: identity.schema_id }) - .then((response) => response.data as KratosSchema); + const detailIdentitySessions = pmAccessUserSession && await listIdentitySessions(detailIdentityId); + + const detailIdentitySchema = await getIdentitySchema(detailIdentity.schema_id) + .then((response) => response as KratosSchema); const addresses = mergeAddresses( - identity.recovery_addresses ?? [], - identity.verifiable_addresses ?? [], + detailIdentity.recovery_addresses ?? [], + detailIdentity.verifiable_addresses ?? [], ); return (

{addresses[0].value}

-

{identity.id}

+

{detailIdentity.id}

- - - Traits - All identity properties specified in the identity schema - - - - - + { + pmAccessUserTrait ? + + + Traits + All identity properties specified in the identity + schema + + + + + + : + + } Actions Quick actions to manage the identity - + - - - Addresses - All linked addresses for verification and recovery - - + { + pmAccessUserAddress ? + + + Addresses + All linked addresses for verification and recovery + + - - - - Type - Value - - - - { - addresses.map((address) => { - return ( - - {address.value} - {address.via} - - {address.verifiable_id && - - Verifiable - { - address.verified ? - - : - +
+ + + Type + Value + + + + { + addresses.map((address) => { + return ( + + {address.value} + {address.via} + + {address.verifiable_id && + + Verifiable + { + address.verified ? + + : + + } + } - - } - {address.recovery_id && - Recovery - } - - - ); - }) - } - -
-
-
- - - Credentials - All authentication mechanisms registered with this identity - - - - - - - - Sessions - See and manage all sessions of this identity - - - - - - OS - Browser - Active since - - - + {address.recovery_id && + Recovery + } + + + ); + }) + } + +
+
+
+ : + + } + { + pmAccessUserCredential ? + + + Credentials + All authentication mechanisms registered with this + identity + + + + + + : + + } + { + pmAccessUserSession ? + + + Sessions + See and manage all sessions of this identity + + { - sessions ? - sessions.map((session) => { - - const device = session.devices![0]; - const parser = new UAParser(device.user_agent); - const result = parser.getResult(); - - return ( - - - {result.os.name} - {result.os.version} - - - {result.browser.name} - {result.browser.version} - - - {new Date(session.authenticated_at!).toLocaleString()} - + detailIdentitySessions ? + + + + OS + Browser + Active since - ); - }) + + + { + detailIdentitySessions.map((session) => { + + const device = session.devices![0]; + const parser = new UAParser(device.user_agent); + const result = parser.getResult(); + + return ( + + + {result.os.name} + {result.os.version} + + + {result.browser.name} + {result.browser.version} + + + {new Date(session.authenticated_at!).toLocaleString()} + + + ); + }) + } + +
: - +

This user has no active sessions

} - - -
-
+
+
+ : + + }
); diff --git a/dashboard/src/app/(inside)/user/data-table.tsx b/dashboard/src/app/(inside)/user/data-table.tsx index 510ee6c..69a1c4b 100644 --- a/dashboard/src/app/(inside)/user/data-table.tsx +++ b/dashboard/src/app/(inside)/user/data-table.tsx @@ -33,9 +33,15 @@ interface IdentityDataTableProps { data: Identity[]; page: number; query: string; + permission: { + pmEditUser: boolean; + pmDeleteUser: boolean; + pmEditUserState: boolean; + pmDeleteUserSession: boolean; + }; } -export function IdentityDataTable({ data, page, query }: IdentityDataTableProps) { +export function IdentityDataTable({ data, page, query, permission }: IdentityDataTableProps) { const columns: ColumnDef[] = [ { @@ -137,6 +143,7 @@ export function IdentityDataTable({ data, page, query }: IdentityDataTableProps) setCurrentIdentity(identity); setIdentitySessionVisible(true); }} + disabled={!permission.pmDeleteUserSession} className="flex items-center space-x-2 text-red-500"> Delete sessions @@ -148,6 +155,7 @@ export function IdentityDataTable({ data, page, query }: IdentityDataTableProps) setCurrentIdentity(identity); setBlockIdentityVisible(true); }} + disabled={!permission.pmEditUserState} className="flex items-center space-x-2 text-red-500"> Block identity @@ -160,6 +168,7 @@ export function IdentityDataTable({ data, page, query }: IdentityDataTableProps) setCurrentIdentity(identity); setUnblockIdentityVisible(true); }} + disabled={!permission.pmEditUserState} className="flex items-center space-x-2 text-red-500"> Unblock identity @@ -170,6 +179,7 @@ export function IdentityDataTable({ data, page, query }: IdentityDataTableProps) setCurrentIdentity(identity); setDeleteIdentityVisible(true); }} + disabled={!permission.pmDeleteUser} className="flex items-center space-x-2 text-red-500"> Delete identity diff --git a/dashboard/src/app/(inside)/user/page.tsx b/dashboard/src/app/(inside)/user/page.tsx index efb1095..8218dc3 100644 --- a/dashboard/src/app/(inside)/user/page.tsx +++ b/dashboard/src/app/(inside)/user/page.tsx @@ -3,6 +3,9 @@ import { IdentityDataTable } from '@/app/(inside)/user/data-table'; import { SearchInput } from '@/components/search-input'; import { queryIdentities } from '@/lib/action/identity'; import { IdentityPagination } from '@/components/pagination'; +import { checkPermission, requirePermission, requireSession } from '@/lib/action/authentication'; +import InsufficientPermission from '@/components/insufficient-permission'; +import { permission, relation } from '@/lib/permission'; export default async function UserPage( { @@ -12,6 +15,17 @@ export default async function UserPage( }, ) { + const session = await requireSession(); + const identityId = session.identity!.id; + + await requirePermission(permission.stack.dashboard, relation.access, identityId); + + const pmAccessUser = await checkPermission(permission.user.it, relation.access, identityId); + const pmEditUser = await checkPermission(permission.user.it, relation.edit, identityId); + const pmDeleteUser = await checkPermission(permission.user.it, relation.delete, identityId); + const pmEditUserState = await checkPermission(permission.user.state, relation.edit, identityId); + const pmDeleteUserSession = await checkPermission(permission.user.session, relation.delete, identityId); + const params = await searchParams; const page = params.page ? Number(params.page) : 1; @@ -20,7 +34,7 @@ export default async function UserPage( let pageSize = 50; let paginationRange = 11; - const { data, itemCount, pageCount } = await queryIdentities({ page, pageSize, query }); + const users = pmAccessUser && await queryIdentities(page, pageSize, query); return (
@@ -31,23 +45,45 @@ export default async function UserPage(

- -
-

{itemCount} item{itemCount && itemCount > 1 ? 's' : ''} found

- -
- + { + !pmAccessUser && ( + + ) + } + { + pmAccessUser && users && ( + <> + +
+

{users.itemCount} item{users.itemCount && users.itemCount > 1 ? 's' : ''} found

+ +
+ + + ) + }
); diff --git a/dashboard/src/components/dynamic-form.tsx b/dashboard/src/components/dynamic-form.tsx index 9020d46..f36cde4 100644 --- a/dashboard/src/components/dynamic-form.tsx +++ b/dashboard/src/components/dynamic-form.tsx @@ -15,6 +15,7 @@ interface DynamicFormProps { onValid: SubmitHandler, onInvalid: SubmitErrorHandler, submitLabel?: string, + disabled?: boolean, } export function DynamicForm( @@ -25,6 +26,7 @@ export function DynamicForm( onValid, onInvalid, submitLabel, + disabled, }: DynamicFormProps, ) { @@ -48,7 +50,7 @@ export function DynamicForm( key={fullFieldName} render={({ field }) => ( - + {key} )} @@ -65,7 +67,7 @@ export function DynamicForm( {value.title} - + {value.description} @@ -87,7 +89,7 @@ export function DynamicForm( diff --git a/dashboard/src/components/identity/identity-actions.tsx b/dashboard/src/components/identity/identity-actions.tsx index 0ddcf32..7606af3 100644 --- a/dashboard/src/components/identity/identity-actions.tsx +++ b/dashboard/src/components/identity/identity-actions.tsx @@ -28,12 +28,21 @@ import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; interface IdentityActionProps { - identity: Identity; + identity: Identity, + permissions: { + pmDeleteUser: boolean; + pmEditUserState: boolean; + pmDeleteUserSession: boolean; + pmCreateUserCode: boolean; + pmCreateUserLink: boolean; + } } -export function IdentityActions({ identity }: IdentityActionProps, +export function IdentityActions({ identity, permissions }: IdentityActionProps, ) { + console.log('IdentityActions', 'Permissions', permissions); + const router = useRouter(); const [dialogVisible, setDialogVisible] = useState(false); @@ -122,7 +131,10 @@ export function IdentityActions({ identity }: IdentityActionProps, dialogDescription="Are you sure you want to create a recovery code for this identity?" dialogButtonSubmit="Create code" > - @@ -142,7 +154,10 @@ export function IdentityActions({ identity }: IdentityActionProps, dialogDescription="Are you sure you want to create a recovery link for this identity?" dialogButtonSubmit="Create link" > - @@ -160,7 +175,10 @@ export function IdentityActions({ identity }: IdentityActionProps, dialogDescription="Are you sure you want to deactivate this identity? The user will not be able to sign-in or use any active session until re-activation!" dialogButtonSubmit="Deactivate" > - @@ -176,7 +194,10 @@ export function IdentityActions({ identity }: IdentityActionProps, dialogDescription="Are you sure you want to activate this identity?" dialogButtonSubmit="Activate" > - @@ -194,7 +215,10 @@ export function IdentityActions({ identity }: IdentityActionProps, dialogButtonSubmit="Invalidate sessions" dialogButtonSubmitProps={{ variant: 'destructive' }} > - @@ -214,7 +238,10 @@ export function IdentityActions({ identity }: IdentityActionProps, dialogButtonSubmit="Delete identity" dialogButtonSubmitProps={{ variant: 'destructive' }} > - diff --git a/dashboard/src/components/identity/identity-credentials.tsx b/dashboard/src/components/identity/identity-credentials.tsx index f362971..78e1fe6 100644 --- a/dashboard/src/components/identity/identity-credentials.tsx +++ b/dashboard/src/components/identity/identity-credentials.tsx @@ -36,7 +36,7 @@ export function IdentityCredentials({ identity }: IdentityCredentialsProps) { ( { - deleteIdentityCredential({ id: identity.id, type: key as never }) + deleteIdentityCredential(identity.id, key as never) .then(() => toast.success(`Credential ${key} deleted`)) .catch(() => toast.error(`Deleting credential ${key} failed`)); }} diff --git a/dashboard/src/components/identity/identity-traits.tsx b/dashboard/src/components/identity/identity-traits.tsx index 1606db4..1a9205c 100644 --- a/dashboard/src/components/identity/identity-traits.tsx +++ b/dashboard/src/components/identity/identity-traits.tsx @@ -16,9 +16,10 @@ import { useState } from 'react'; interface IdentityTraitFormProps { schema: KratosSchema; identity: Identity; + disabled: boolean; } -export function IdentityTraits({ schema, identity }: IdentityTraitFormProps) { +export function IdentityTraits({ schema, identity, disabled }: IdentityTraitFormProps) { const [currentIdentity, setCurrentIdentity] = useState(identity); @@ -47,16 +48,16 @@ export function IdentityTraits({ schema, identity }: IdentityTraitFormProps) { delete traits['metadata_public']; delete traits['metadata_admin']; - updateIdentity({ - id: currentIdentity.id, - body: { + updateIdentity( + currentIdentity.id, + { schema_id: currentIdentity.schema_id, state: currentIdentity.state!, traits: traits, metadata_public: data.metadata_public, metadata_admin: data.metadata_admin, }, - }) + ) .then((identity) => { setCurrentIdentity(identity); toast.success('Identity updated'); @@ -74,10 +75,11 @@ export function IdentityTraits({ schema, identity }: IdentityTraitFormProps) { return ( Public Metadata -