feat: publish HoloLake model-native living system source
This commit is contained in:
parent
6ad10edde1
commit
c395dd3a99
2467 changed files with 615073 additions and 0 deletions
250
product-source/hololake-platform/src/utils/vaultAttachments.ts
Normal file
250
product-source/hololake-platform/src/utils/vaultAttachments.ts
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { canWritePathToVault } from './vaultPathContainment'
|
||||
|
||||
const LOCALHOST_ASSET_URL_PREFIX = 'asset://localhost/'
|
||||
const HTTP_ASSET_URL_PREFIX = 'http://asset.localhost/'
|
||||
const GENERIC_ASSET_URL_PREFIX = 'asset://'
|
||||
const ASSET_URL_PREFIXES = [
|
||||
LOCALHOST_ASSET_URL_PREFIX,
|
||||
HTTP_ASSET_URL_PREFIX,
|
||||
GENERIC_ASSET_URL_PREFIX,
|
||||
]
|
||||
const ATTACHMENTS_SEGMENT = '/attachments/'
|
||||
const RELATIVE_ATTACHMENTS_PREFIX = 'attachments/'
|
||||
const WINDOWS_EXTENDED_PATH_PREFIX = '\\\\?\\'
|
||||
const WINDOWS_EXTENDED_UNC_PREFIX = '\\\\?\\UNC\\'
|
||||
const WINDOWS_DRIVE_PATH_PATTERN = /^[A-Za-z]:[\\/]/
|
||||
|
||||
type AbsolutePath = string
|
||||
type AttachmentPath = string
|
||||
type VaultPath = string
|
||||
|
||||
type UrlRequest = {
|
||||
url: string
|
||||
}
|
||||
|
||||
type PathRequest = {
|
||||
path: string
|
||||
}
|
||||
|
||||
type VaultPathRequest = {
|
||||
vaultPath: VaultPath
|
||||
}
|
||||
|
||||
type AttachmentPathRequest = {
|
||||
attachmentPath: AttachmentPath
|
||||
}
|
||||
|
||||
export type VaultAttachmentPathRequest = UrlRequest & {
|
||||
vaultPath?: VaultPath
|
||||
}
|
||||
|
||||
export type VaultAttachmentUrlRequest = UrlRequest
|
||||
|
||||
function safeDecode(value: string): string {
|
||||
try {
|
||||
return decodeURIComponent(value)
|
||||
} catch {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
function hasUnsafeRelativeSegment({ path }: PathRequest): boolean {
|
||||
return path.split(/[\\/]/u).some(segment => segment === '..')
|
||||
}
|
||||
|
||||
function usesWindowsSeparators({ path }: PathRequest): boolean {
|
||||
return WINDOWS_DRIVE_PATH_PATTERN.test(path) || path.startsWith('\\\\')
|
||||
}
|
||||
|
||||
function relativePathForVault({
|
||||
attachmentPath,
|
||||
vaultPath,
|
||||
}: AttachmentPathRequest & VaultPathRequest): AttachmentPath {
|
||||
return usesWindowsSeparators({ path: vaultPath })
|
||||
? attachmentPath.replace(/\//g, '\\')
|
||||
: attachmentPath.replace(/\\/g, '/')
|
||||
}
|
||||
|
||||
function removeWindowsExtendedPrefix(path: AbsolutePath): AbsolutePath {
|
||||
if (path.startsWith(WINDOWS_EXTENDED_UNC_PREFIX)) {
|
||||
return `\\\\${path.slice(WINDOWS_EXTENDED_UNC_PREFIX.length)}`
|
||||
}
|
||||
if (path.startsWith(WINDOWS_EXTENDED_PATH_PREFIX)) {
|
||||
return path.slice(WINDOWS_EXTENDED_PATH_PREFIX.length)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
function normalizedFilesystemPath(path: AbsolutePath): AbsolutePath {
|
||||
return removeWindowsExtendedPrefix(path).replace(/\\/g, '/')
|
||||
}
|
||||
|
||||
function withoutTrailingSlash(path: AbsolutePath): AbsolutePath {
|
||||
return path.replace(/\/+$/, '')
|
||||
}
|
||||
|
||||
function normalizeForComparison(path: AbsolutePath, vaultPath: VaultPath): AbsolutePath {
|
||||
const normalizedPath = withoutTrailingSlash(normalizedFilesystemPath(path))
|
||||
const normalizedVaultPath = withoutTrailingSlash(normalizedFilesystemPath(vaultPath))
|
||||
return WINDOWS_DRIVE_PATH_PATTERN.test(normalizedPath)
|
||||
|| WINDOWS_DRIVE_PATH_PATTERN.test(normalizedVaultPath)
|
||||
? normalizedPath.toLowerCase()
|
||||
: normalizedPath
|
||||
}
|
||||
|
||||
function assetUrlPrefix({ url }: UrlRequest): string | null {
|
||||
return ASSET_URL_PREFIXES.find(prefix => url.startsWith(prefix)) ?? null
|
||||
}
|
||||
|
||||
function isRootedPath({ path }: PathRequest): boolean {
|
||||
if (path.startsWith('/')) return true
|
||||
if (WINDOWS_DRIVE_PATH_PATTERN.test(path)) return true
|
||||
return path.startsWith('\\\\')
|
||||
}
|
||||
|
||||
function restoreUnixRoot({ path }: PathRequest): AbsolutePath {
|
||||
return isRootedPath({ path }) ? path : `/${path}`
|
||||
}
|
||||
|
||||
function resolveAssetPath({ url }: UrlRequest): AbsolutePath | null {
|
||||
const prefix = assetUrlPrefix({ url })
|
||||
if (!prefix) return null
|
||||
return restoreUnixRoot({ path: safeDecode(url.slice(prefix.length)) })
|
||||
}
|
||||
|
||||
function extractPortableAttachmentPath({ path }: PathRequest): AttachmentPath | null {
|
||||
const normalizedPath = normalizedFilesystemPath(path)
|
||||
const index = normalizedPath.lastIndexOf(ATTACHMENTS_SEGMENT)
|
||||
if (index === -1) return null
|
||||
|
||||
const filename = normalizedPath.slice(index + ATTACHMENTS_SEGMENT.length)
|
||||
return filename ? `${RELATIVE_ATTACHMENTS_PREFIX}${filename}` : null
|
||||
}
|
||||
|
||||
function currentVaultAttachmentPath({
|
||||
path,
|
||||
vaultPath,
|
||||
}: PathRequest & VaultPathRequest): AttachmentPath | null {
|
||||
const normalizedPath = normalizedFilesystemPath(path)
|
||||
const normalizedVaultPath = withoutTrailingSlash(normalizedFilesystemPath(vaultPath))
|
||||
const attachmentsRoot = `${normalizedVaultPath}/${RELATIVE_ATTACHMENTS_PREFIX}`
|
||||
const comparablePath = normalizeForComparison(normalizedPath, vaultPath)
|
||||
const comparableRoot = normalizeForComparison(attachmentsRoot, vaultPath)
|
||||
if (!comparablePath.startsWith(comparableRoot)) return null
|
||||
|
||||
const filename = normalizedPath.slice(attachmentsRoot.length)
|
||||
return filename ? `${RELATIVE_ATTACHMENTS_PREFIX}${filename}` : null
|
||||
}
|
||||
|
||||
function isPathInsideVault({
|
||||
path,
|
||||
vaultPath,
|
||||
}: PathRequest & VaultPathRequest): boolean {
|
||||
return canWritePathToVault(
|
||||
removeWindowsExtendedPrefix(path),
|
||||
removeWindowsExtendedPrefix(vaultPath),
|
||||
)
|
||||
}
|
||||
|
||||
function resolveRelativeAttachmentPath({
|
||||
url,
|
||||
vaultPath,
|
||||
}: UrlRequest & VaultPathRequest): AbsolutePath | null {
|
||||
if (!url.startsWith(RELATIVE_ATTACHMENTS_PREFIX)) return null
|
||||
|
||||
const attachmentPath = safeDecode(url)
|
||||
if (hasUnsafeRelativeSegment({ path: attachmentPath })) return null
|
||||
return vaultAttachmentPath({ vaultPath, attachmentPath })
|
||||
}
|
||||
|
||||
export function vaultAttachmentPath({
|
||||
attachmentPath,
|
||||
vaultPath,
|
||||
}: AttachmentPathRequest & VaultPathRequest): AbsolutePath {
|
||||
const separator = usesWindowsSeparators({ path: vaultPath }) ? '\\' : '/'
|
||||
const normalizedAttachmentPath = relativePathForVault({ vaultPath, attachmentPath })
|
||||
const joiner = vaultPath.endsWith('/') || vaultPath.endsWith('\\') ? '' : separator
|
||||
return `${vaultPath}${joiner}${normalizedAttachmentPath}`
|
||||
}
|
||||
|
||||
export function attachmentAssetUrlFromPath({ path }: PathRequest): string {
|
||||
return convertFileSrc(path)
|
||||
}
|
||||
|
||||
export function vaultAttachmentAssetUrl({
|
||||
attachmentPath,
|
||||
vaultPath,
|
||||
}: AttachmentPathRequest & VaultPathRequest): string {
|
||||
return attachmentAssetUrlFromPath({
|
||||
path: vaultAttachmentPath({ vaultPath, attachmentPath }),
|
||||
})
|
||||
}
|
||||
|
||||
export function isPortableAttachmentPath({ path }: PathRequest): boolean {
|
||||
return path.startsWith(RELATIVE_ATTACHMENTS_PREFIX)
|
||||
}
|
||||
|
||||
export function isTauriAssetUrl({ url }: UrlRequest): boolean {
|
||||
return assetUrlPrefix({ url }) !== null
|
||||
}
|
||||
|
||||
export function filesystemPathFromAssetUrl({ url }: UrlRequest): AbsolutePath | null {
|
||||
return resolveAssetPath({ url })
|
||||
}
|
||||
|
||||
export function isCurrentVaultAssetUrl({
|
||||
url,
|
||||
vaultPath,
|
||||
}: UrlRequest & VaultPathRequest): boolean {
|
||||
const path = resolveAssetPath({ url })
|
||||
return path ? isPathInsideVault({ path, vaultPath }) : false
|
||||
}
|
||||
|
||||
export function portableAttachmentPathFromCurrentVaultAssetUrl({
|
||||
url,
|
||||
vaultPath,
|
||||
}: UrlRequest & VaultPathRequest): AttachmentPath | null {
|
||||
const path = resolveAssetPath({ url })
|
||||
if (!path || !isPathInsideVault({ path, vaultPath })) return null
|
||||
return currentVaultAttachmentPath({ path, vaultPath })
|
||||
}
|
||||
|
||||
export function portableAttachmentPathFromCurrentVaultPath({
|
||||
path,
|
||||
vaultPath,
|
||||
}: PathRequest & VaultPathRequest): AttachmentPath | null {
|
||||
if (!isPathInsideVault({ path, vaultPath })) return null
|
||||
return currentVaultAttachmentPath({ path, vaultPath })
|
||||
}
|
||||
|
||||
export function portableAttachmentPathFromAnyAssetUrl({ url }: UrlRequest): AttachmentPath | null {
|
||||
const path = resolveAssetPath({ url })
|
||||
return path ? extractPortableAttachmentPath({ path }) : null
|
||||
}
|
||||
|
||||
export function isVaultAttachmentUrl({ url }: VaultAttachmentUrlRequest): boolean {
|
||||
const trimmedUrl = url.trim()
|
||||
return isPortableAttachmentPath({ path: trimmedUrl })
|
||||
|| isTauriAssetUrl({ url: trimmedUrl })
|
||||
}
|
||||
|
||||
export function resolveVaultAttachmentPath({
|
||||
url,
|
||||
vaultPath,
|
||||
}: VaultAttachmentPathRequest): AbsolutePath | null {
|
||||
const trimmedVaultPath = vaultPath?.trim()
|
||||
if (!trimmedVaultPath) return null
|
||||
|
||||
const trimmedUrl = url.trim()
|
||||
if (!trimmedUrl) return null
|
||||
|
||||
const candidatePath = resolveRelativeAttachmentPath({
|
||||
url: trimmedUrl,
|
||||
vaultPath: trimmedVaultPath,
|
||||
})
|
||||
?? resolveAssetPath({ url: trimmedUrl })
|
||||
?? trimmedUrl
|
||||
|
||||
return isPathInsideVault({ path: candidatePath, vaultPath: trimmedVaultPath }) ? candidatePath : null
|
||||
}
|
||||
Loading…
Reference in a new issue