Files
speckle-server/packages/server/modules/workspaces/domain/logic.ts
T
Chuck Driesler e6e65a2f7d feat(sso): list sso associations by user email (#3420)
* feat(workspaces): add workspace sso feature flag

* feat(workspaceSso): wip validate sso

* feat(workspaces): validate and add sso provider to the workspace with user sso sessions

* feat(workspaces): validate and add sso provider to the workspace with user sso sessions

* WIP

* fix(sso): restructure to handle all branches at end of flow

* fix(sso): add and validate emails used for sso

* fix(sso): park progress

* chore(workspaces): review sso login/valdate

* fix(sso): adjust validate url

* chore(sso): auth header puzzle

* fix(sso): happy-path config

* chore(gql): gqlgen

* fix(sso): almost almost

* fix(sso): auth endpoint

* a lil more terse

* fix(sso): light at the end of the tunnel

* fix(sso): improve catch block error messages

* fix(sso): session lifespan => validUntil

* fix(sso): I think we've got it

* feat(sso): limited workspace values for public sso login

* fix(sso): use factory functions

* fix(sso): til decrypt is single-use

* fix(sso): correct usage of access codes

* fix(sso): use finalize middleware in all routes

* chore(sso): cheeky tweak

* fix(sso): move some types around

* fix(sso): stencil final shape I'm sleepy

* fix(sso): more factories more factories

* fix(sso): on to final boss of factories

* fix(sso): needs a haircut but she works

* fix(sso): init rest w function, not side-effects

* fix(sso): /authn => /sso

* chore(sso): errors

* chore(sso): test test test

* chore(sso): test all the corners

* feat(sso): list workspace sso memberships

* chore(sso): tests, expose in rest

* fix(sso): expose search via gql

---------

Co-authored-by: Gergő Jedlicska <gergo@jedlicska.com>
Co-authored-by: Mike Tasset <mike.tasset@gmail.com>
2024-11-01 11:27:12 +01:00

81 lines
2.2 KiB
TypeScript

import { UserEmail } from '@/modules/core/domain/userEmails/types'
import {
WorkspaceDomainsInvalidState,
WorkspaceInvalidUpdateError
} from '@/modules/workspaces/errors/workspace'
import {
LimitedWorkspace,
Workspace,
WorkspaceDefaultProjectRole,
WorkspaceDomain
} from '@/modules/workspacesCore/domain/types'
import { Roles, WorkspaceRoles } from '@speckle/shared'
import { pick } from 'lodash'
export const userEmailsCompliantWithWorkspaceDomains = ({
userEmails,
workspaceDomains
}: {
userEmails: UserEmail[]
workspaceDomains: WorkspaceDomain[]
}): boolean =>
anyEmailCompliantWithWorkspaceDomains({
emails: userEmails.filter((e) => e.verified).map((e) => e.email),
workspaceDomains
})
export const anyEmailCompliantWithWorkspaceDomains = ({
emails,
workspaceDomains
}: {
emails: string[]
workspaceDomains: WorkspaceDomain[]
}): boolean => {
const validWorkspaceDomains = workspaceDomains.filter((domain) => domain.verified)
// we must have min 1 domain to validate compliance
if (!validWorkspaceDomains.length) throw new WorkspaceDomainsInvalidState()
for (const email of emails) {
if (validWorkspaceDomains.some((domain) => email.endsWith(domain.domain)))
return true
}
return false
}
/**
* Given an optional string value, assert it is a valid default project role and return it.
*/
export const parseDefaultProjectRole = (
role?: string | null
): WorkspaceDefaultProjectRole | null => {
if (!role) return null
const isValidRole = (role: string): role is WorkspaceDefaultProjectRole => {
const validRoles: string[] = [Roles.Stream.Reviewer, Roles.Stream.Contributor]
return validRoles.includes(role)
}
if (!isValidRole(role)) {
throw new WorkspaceInvalidUpdateError('Provided default project role is invalid')
}
return role
}
export const isWorkspaceRole = (role: string): role is WorkspaceRoles => {
const validRoles: string[] = Object.values(Roles.Workspace)
return validRoles.includes(role)
}
export const toLimitedWorkspace = (workspace: Workspace): LimitedWorkspace => {
return pick(workspace, [
'id',
'slug',
'name',
'description',
'logo',
'defaultLogoIndex'
])
}