fix: use workspace id in collaborator (#6447)

Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
Alexander Onnikov 2024-08-30 19:01:03 +07:00 committed by GitHub
parent 699e553e83
commit 202adb5077
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 26 additions and 21 deletions

View File

@ -27,11 +27,11 @@ describe('utils', () => {
describe('parseDocumentId', () => {
expect(parseDocumentId('ws1://doc1:HEAD' as DocumentId)).toEqual({
workspaceUrl: 'ws1',
workspaceId: 'ws1',
collaborativeDoc: 'doc1:HEAD:HEAD' as CollaborativeDoc
})
expect(parseDocumentId('ws1://doc1:HEAD/doc2:v2' as DocumentId)).toEqual({
workspaceUrl: 'ws1',
workspaceId: 'ws1',
collaborativeDoc: 'doc1:HEAD:HEAD#doc2:v2:v2' as CollaborativeDoc
})
})

View File

@ -36,7 +36,7 @@ import { DocumentId, PlatformDocumentId } from './types'
*
* @public
*/
export function formatDocumentId (workspaceUrl: string, collaborativeDoc: CollaborativeDoc): DocumentId {
export function formatDocumentId (workspaceId: string, collaborativeDoc: CollaborativeDoc): DocumentId {
const path = collaborativeDocUnchain(collaborativeDoc)
.map((p) => {
const { documentId, versionId } = collaborativeDocParse(p)
@ -44,15 +44,15 @@ export function formatDocumentId (workspaceUrl: string, collaborativeDoc: Collab
})
.join('/')
return `${workspaceUrl}://${path}` as DocumentId
return `${workspaceId}://${path}` as DocumentId
}
/** @public */
export function parseDocumentId (documentId: DocumentId): {
workspaceUrl: string
workspaceId: string
collaborativeDoc: CollaborativeDoc
} {
const [workspaceUrl, path] = documentId.split('://')
const [workspaceId, path] = documentId.split('://')
const segments = path.split('/')
const collaborativeDocs = segments.map((p) => {
@ -61,7 +61,7 @@ export function parseDocumentId (documentId: DocumentId): {
})
return {
workspaceUrl,
workspaceId,
collaborativeDoc: collaborativeDocChain(...collaborativeDocs)
}
}

View File

@ -18,7 +18,6 @@ import { PlatformError, Severity, Status, getMetadata } from '@hcengineering/pla
import { v4 as uuid } from 'uuid'
import plugin from './plugin'
import { decodeTokenPayload } from './utils'
interface FileUploadError {
key: string
@ -42,8 +41,8 @@ function getFilesUrl (): string {
return filesUrl.includes('://') ? filesUrl : concatLink(frontUrl, filesUrl)
}
export function getCurrentWorkspace (): string {
return decodeTokenPayload(getMetadata(plugin.metadata.Token) ?? '').workspace
export function getCurrentWorkspaceId (): string {
return getMetadata(plugin.metadata.WorkspaceId) ?? ''
}
/**
@ -59,7 +58,7 @@ export function generateFileId (): string {
export function getUploadUrl (): string {
const template = getMetadata(plugin.metadata.UploadURL) ?? defaultUploadUrl
return template.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspace()))
return template.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspaceId()))
}
/**
@ -73,7 +72,7 @@ export function getFileUrl (file: string, filename?: string): string {
const template = getFilesUrl()
return template
.replaceAll(':filename', encodeURIComponent(filename ?? file))
.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspace()))
.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspaceId()))
.replaceAll(':blobId', encodeURIComponent(file))
}

View File

@ -135,6 +135,7 @@ export default plugin(presentationId, {
Token: '' as Metadata<string>,
Endpoint: '' as Metadata<string>,
Workspace: '' as Metadata<string>,
WorkspaceId: '' as Metadata<string>,
FrontUrl: '' as Asset,
PreviewConfig: '' as Metadata<PreviewConfig | undefined>,
ClientHook: '' as Metadata<ClientHook>,

View File

@ -2,14 +2,14 @@ import type { Blob, Ref } from '@hcengineering/core'
import { concatLink } from '@hcengineering/core'
import { getMetadata } from '@hcengineering/platform'
import { getFileUrl, getCurrentWorkspace } from './file'
import { getFileUrl, getCurrentWorkspaceId } from './file'
import presentation from './plugin'
export interface PreviewConfig {
previewUrl: string
}
const defaultPreview = (): string => `/files/${getCurrentWorkspace()}?file=:blobId&size=:size`
const defaultPreview = (): string => `/files/${getCurrentWorkspaceId()}?file=:blobId&size=:size`
/**
*
@ -58,7 +58,7 @@ function blobToSrcSet (cfg: PreviewConfig, blob: Ref<Blob>, width: number | unde
return ''
}
let url = cfg.previewUrl.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspace()))
let url = cfg.previewUrl.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspaceId()))
const downloadUrl = getFileUrl(blob)
const frontUrl = getMetadata(presentation.metadata.FrontUrl) ?? window.location.origin

View File

@ -52,6 +52,7 @@ export async function connect (title: string): Promise<Client | undefined> {
setMetadata(presentation.metadata.Token, token)
setMetadata(presentation.metadata.Workspace, workspaceLoginInfo.workspace)
setMetadata(presentation.metadata.WorkspaceId, workspaceLoginInfo.workspaceId)
setMetadata(presentation.metadata.Endpoint, workspaceLoginInfo.endpoint)
if (_token !== token && _client !== undefined) {

View File

@ -441,6 +441,7 @@ export function navigateToWorkspace (
}
setMetadata(presentation.metadata.Token, loginInfo.token)
setMetadata(presentation.metadata.Workspace, loginInfo.workspace)
setMetadata(presentation.metadata.WorkspaceId, loginInfo.workspaceId)
setLoginInfo(loginInfo)
if (navigateUrl !== undefined) {
@ -896,6 +897,7 @@ export async function afterConfirm (clearQuery = false): Promise<void> {
if (result !== undefined) {
setMetadata(presentation.metadata.Token, result.token)
setMetadata(presentation.metadata.Workspace, result.workspace)
setMetadata(presentation.metadata.WorkspaceId, result.workspaceId)
setMetadataLocalStorage(login.metadata.LastToken, result.token)
setLoginInfo(result)

View File

@ -78,6 +78,7 @@ export async function connect (title: string): Promise<Client | undefined> {
token = workspaceLoginInfo.token
setMetadataLocalStorage(login.metadata.LoginTokens, tokens)
setMetadata(presentation.metadata.Workspace, workspaceLoginInfo.workspace)
setMetadata(presentation.metadata.WorkspaceId, workspaceLoginInfo.workspaceId)
}
setMetadata(presentation.metadata.Token, token)
@ -354,6 +355,7 @@ function clearMetadata (ws: string): void {
setMetadata(presentation.metadata.Token, null)
setMetadata(presentation.metadata.Workspace, null)
setMetadata(presentation.metadata.WorkspaceId, null)
setMetadataLocalStorage(login.metadata.LastToken, null)
setMetadataLocalStorage(login.metadata.LoginEndpoint, null)
setMetadataLocalStorage(login.metadata.LoginEmail, null)

View File

@ -35,19 +35,19 @@ export class AuthenticationExtension implements Extension {
async onAuthenticate (data: onAuthenticatePayload): Promise<Context> {
const ctx = this.configuration.ctx
const { workspaceUrl: workspace, collaborativeDoc } = parseDocumentId(data.documentName as DocumentId)
const { workspaceId, collaborativeDoc } = parseDocumentId(data.documentName as DocumentId)
return await ctx.with('authenticate', { workspace }, async () => {
return await ctx.with('authenticate', { workspaceId }, async () => {
const token = decodeToken(data.token)
ctx.info('authenticate', { workspace, mode: token.extra?.mode ?? '' })
ctx.info('authenticate', { workspaceId, mode: token.extra?.mode ?? '' })
// verify workspace can be accessed with the token
const workspaceInfo = await getWorkspaceInfo(data.token)
// verify workspace url in the document matches the token
if (workspaceInfo.workspace !== workspace) {
throw new Error('documentName must include workspace')
if (workspaceInfo.workspace !== workspaceId) {
throw new Error('documentName must include workspace id')
}
data.connection.readOnly = isReadonlyDoc(collaborativeDoc)

View File

@ -17,7 +17,7 @@ import type { Class, Doc, Domain, Ref } from '@hcengineering/core'
/** @public */
export interface DocumentId {
workspaceUrl: string
workspaceId: string
documentId: string
versionId: string
}