Files
speckle-server/packages/frontend-2/middleware/requireValidProject.ts
T
andrewwallacespeckle d3931f1855 feat(fe2): Frontend SSO Integration (#3464)
* Readd work from old branch

* Improved Login.vue

* Replace watch with onResult

* Server: Error improvement

* FE Middleware

* Update style

* Delete Sso. Mixpanel events

* Updates

* Improved loading state

* Invites. Register sso page

* Middleware improvements. Session error no logout

* Changes from deisgns

* Swap button to LayoutMenu

* Improve middleware

* Remove typo

* Fix errormessage

* Remove edit functionality

* New composable file for sso

* Improved names for composables. Tidyups

* Reactive errors

* Reorder Login.vue

* Improved Typeguard

* Enum

* Comments from Mike

* Add error toast

* Remove FormButton from LoginButtonBase

* Use linkComponent prop

* Move workspace select to new component

* Fragmentation

* Fix loading useFetch

* use WorkspaceAvatar

* Feature flag sso button

* Update fragment name

* Skip middleware during auth flow

* Add rules to Workspace Selector

* Reactive useWorkspacePublicSsoCheck

* AuthRegisterNewsletter types

* v-bind on Select

* Fragment WrapperSecurity

* Remove useForm from Form.vue

* Reactive values in composables

* Prevent infinite loading when no invite found

* useWorkspaceSsoValidation maybeRef

* Added comment to requireSsoEnabled

* Bugfix

* Update Button.vue

* Fix form

* Update valid model middleware

* Update LoginButtonBase.vue

* NewsletterConset ref

* use setFieldValue

* Update Login.vue

* Swap mayberef to ref

* Comments from PR

* Changes from call with Fabs

* Fix session-error bug

* Fix circleci

* Small fix to index
2024-11-21 12:50:57 +00:00

81 lines
2.3 KiB
TypeScript

import { ProjectVisibility } from '~/lib/common/generated/gql/graphql'
import { WorkspaceSsoErrorCodes } from '~/lib/workspaces/helpers/types'
import { useApolloClientFromNuxt } from '~~/lib/common/composables/graphql'
import {
convertThrowIntoFetchResult,
getFirstErrorMessage
} from '~~/lib/common/helpers/graphql'
import { projectAccessCheckQuery } from '~~/lib/projects/graphql/queries'
/**
* Used in project page to validate that project ID refers to a valid project and redirects to 404 if not
*/
export default defineNuxtRouteMiddleware(async (to) => {
const projectId = to.params.id as string
const client = useApolloClientFromNuxt()
const { data, errors } = await client
.query({
query: projectAccessCheckQuery,
variables: { id: projectId },
context: {
skipLoggingErrors: true
},
fetchPolicy: 'network-only'
})
.catch(convertThrowIntoFetchResult)
// If project is public or link shareable, allow access regardless of SSO
if (
data?.project?.visibility === ProjectVisibility.Public ||
data?.project?.visibility === ProjectVisibility.Unlisted
) {
return
}
// Check for SSO session error
const ssoSessionError = (errors || []).find(
(e) => e.extensions?.['code'] === WorkspaceSsoErrorCodes.SESSION_MISSING_OR_EXPIRED
)
// If we have an SSO error, the message contains the workspace slug
if (ssoSessionError) {
const workspaceSlug = ssoSessionError.message
return navigateTo(`/workspaces/${workspaceSlug}/sso/session-error`)
}
// If project successfully resolved and isn't public or link shareable, continue with normal flow
if (data?.project?.id) {
return
}
const isForbidden = (errors || []).find((e) => e.extensions?.['code'] === 'FORBIDDEN')
const isNotFound = (errors || []).find(
(e) => e.extensions?.['code'] === 'STREAM_NOT_FOUND'
)
if (isNotFound) {
return abortNavigation(
createError({ statusCode: 404, message: 'Project not found' })
)
}
if (isForbidden) {
return abortNavigation(
createError({
statusCode: 403,
message: 'You do not have access to this project'
})
)
}
if (errors?.length) {
return abortNavigation(
createError({
statusCode: 500,
message: getFirstErrorMessage(errors) || 'An unexpected error occurred'
})
)
}
})