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', () => { describe('parseDocumentId', () => {
expect(parseDocumentId('ws1://doc1:HEAD' as DocumentId)).toEqual({ expect(parseDocumentId('ws1://doc1:HEAD' as DocumentId)).toEqual({
workspaceUrl: 'ws1', workspaceId: 'ws1',
collaborativeDoc: 'doc1:HEAD:HEAD' as CollaborativeDoc collaborativeDoc: 'doc1:HEAD:HEAD' as CollaborativeDoc
}) })
expect(parseDocumentId('ws1://doc1:HEAD/doc2:v2' as DocumentId)).toEqual({ expect(parseDocumentId('ws1://doc1:HEAD/doc2:v2' as DocumentId)).toEqual({
workspaceUrl: 'ws1', workspaceId: 'ws1',
collaborativeDoc: 'doc1:HEAD:HEAD#doc2:v2:v2' as CollaborativeDoc collaborativeDoc: 'doc1:HEAD:HEAD#doc2:v2:v2' as CollaborativeDoc
}) })
}) })

View File

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

View File

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

View File

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

View File

@ -2,14 +2,14 @@ import type { Blob, Ref } from '@hcengineering/core'
import { concatLink } from '@hcengineering/core' import { concatLink } from '@hcengineering/core'
import { getMetadata } from '@hcengineering/platform' import { getMetadata } from '@hcengineering/platform'
import { getFileUrl, getCurrentWorkspace } from './file' import { getFileUrl, getCurrentWorkspaceId } from './file'
import presentation from './plugin' import presentation from './plugin'
export interface PreviewConfig { export interface PreviewConfig {
previewUrl: string 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 '' return ''
} }
let url = cfg.previewUrl.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspace())) let url = cfg.previewUrl.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspaceId()))
const downloadUrl = getFileUrl(blob) const downloadUrl = getFileUrl(blob)
const frontUrl = getMetadata(presentation.metadata.FrontUrl) ?? window.location.origin 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.Token, token)
setMetadata(presentation.metadata.Workspace, workspaceLoginInfo.workspace) setMetadata(presentation.metadata.Workspace, workspaceLoginInfo.workspace)
setMetadata(presentation.metadata.WorkspaceId, workspaceLoginInfo.workspaceId)
setMetadata(presentation.metadata.Endpoint, workspaceLoginInfo.endpoint) setMetadata(presentation.metadata.Endpoint, workspaceLoginInfo.endpoint)
if (_token !== token && _client !== undefined) { if (_token !== token && _client !== undefined) {

View File

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

View File

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

View File

@ -35,19 +35,19 @@ export class AuthenticationExtension implements Extension {
async onAuthenticate (data: onAuthenticatePayload): Promise<Context> { async onAuthenticate (data: onAuthenticatePayload): Promise<Context> {
const ctx = this.configuration.ctx 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) 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 // verify workspace can be accessed with the token
const workspaceInfo = await getWorkspaceInfo(data.token) const workspaceInfo = await getWorkspaceInfo(data.token)
// verify workspace url in the document matches the token // verify workspace url in the document matches the token
if (workspaceInfo.workspace !== workspace) { if (workspaceInfo.workspace !== workspaceId) {
throw new Error('documentName must include workspace') throw new Error('documentName must include workspace id')
} }
data.connection.readOnly = isReadonlyDoc(collaborativeDoc) data.connection.readOnly = isReadonlyDoc(collaborativeDoc)

View File

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