diff --git a/.eslintrc.js b/.eslintrc.js index df44d24e58..95b8077bf6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -242,6 +242,7 @@ module.exports = { 'packages/@uppy/utils/src/**/*.js', 'packages/@uppy/vue/src/**/*.js', 'packages/@uppy/webcam/src/**/*.js', + 'packages/@uppy/webdav/src/**/*.js', 'packages/@uppy/xhr-upload/src/**/*.js', 'packages/@uppy/zoom/src/**/*.js', ], diff --git a/packages/@uppy/companion/package.json b/packages/@uppy/companion/package.json index 8e28728c10..f266003904 100644 --- a/packages/@uppy/companion/package.json +++ b/packages/@uppy/companion/package.json @@ -48,6 +48,7 @@ "express-prom-bundle": "6.5.0", "express-request-id": "1.4.1", "express-session": "1.17.3", + "fast-xml-parser": "^4.2.7", "form-data": "^3.0.0", "got": "11", "grant": "5.4.21", @@ -67,6 +68,7 @@ "serialize-javascript": "^6.0.0", "tus-js-client": "^3.0.0", "validator": "^13.0.0", + "webdav": "^5.3.0", "ws": "8.8.1" }, "devDependencies": { diff --git a/packages/@uppy/companion/src/config/grant.js b/packages/@uppy/companion/src/config/grant.js index 39f80b8328..794cb75750 100644 --- a/packages/@uppy/companion/src/config/grant.js +++ b/packages/@uppy/companion/src/config/grant.js @@ -49,5 +49,16 @@ module.exports = () => { access_url: 'https://zoom.us/oauth/token', callback: '/zoom/callback', }, + webdav: { + transport: 'session', + // use 'subdomain' for full domain (hostname) similar to mastodon: + // https://github.com/simov/grant/blob/6e0692dfdd83edbc4ee82629ba0fe8f986d5879d/config/oauth.json#L631 + dynamic: ['subdomain'], + authorize_url: 'https://[subdomain]/apps/oauth2/authorize', + access_url: 'https://[subdomain]/apps/oauth2/api/v1/token', + scope: ['profile'], + oauth: 2, + callback: '/webdavOauth/callback', + }, } } diff --git a/packages/@uppy/companion/src/server/controllers/get.js b/packages/@uppy/companion/src/server/controllers/get.js index e3bd4da759..fcd54f8038 100644 --- a/packages/@uppy/companion/src/server/controllers/get.js +++ b/packages/@uppy/companion/src/server/controllers/get.js @@ -8,7 +8,7 @@ async function get (req, res) { const { provider } = req.companion async function getSize () { - return provider.size({ id, token: accessToken, query: req.query }) + return provider.size({ id, token: accessToken, providerUserSession, query: req.query }) } async function download () { diff --git a/packages/@uppy/companion/src/server/provider/Provider.js b/packages/@uppy/companion/src/server/provider/Provider.js index e649cab1a6..3508a467bb 100644 --- a/packages/@uppy/companion/src/server/provider/Provider.js +++ b/packages/@uppy/companion/src/server/provider/Provider.js @@ -8,11 +8,12 @@ class Provider { * * @param {{providerName: string, allowLocalUrls: boolean, providerGrantConfig?: object}} options */ - constructor ({ allowLocalUrls, providerGrantConfig }) { + constructor ({ allowLocalUrls, providerGrantConfig, providerOptions }) { // Some providers might need cookie auth for the thumbnails fetched via companion this.needsCookieAuth = false this.allowLocalUrls = allowLocalUrls this.providerGrantConfig = providerGrantConfig + this.providerOptions = providerOptions return this } diff --git a/packages/@uppy/companion/src/server/provider/index.js b/packages/@uppy/companion/src/server/provider/index.js index e0b927dbc8..82df5638a6 100644 --- a/packages/@uppy/companion/src/server/provider/index.js +++ b/packages/@uppy/companion/src/server/provider/index.js @@ -9,6 +9,8 @@ const facebook = require('./facebook') const onedrive = require('./onedrive') const unsplash = require('./unsplash') const zoom = require('./zoom') +const webdavSimpleAuth = require('./webdav/WebdavSimpleAuthProvider') +const webdavOauth = require('./webdav/WebdavOauthProvider') const { getURLBuilder } = require('../helpers/utils') const logger = require('../logger') const { getCredentialsResolver } = require('./credentials') @@ -72,7 +74,9 @@ module.exports.getProviderMiddleware = (providers, grantConfig) => { req.companion.providerGrantConfig = providerGrantConfig } - req.companion.provider = new ProviderClass({ providerName, providerGrantConfig, allowLocalUrls }) + const providerOptions = req.companion.options.providerOptions[providerName] || {} + + req.companion.provider = new ProviderClass({ providerName, providerGrantConfig, providerOptions, allowLocalUrls }) req.companion.providerClass = ProviderClass } else { logger.warn('invalid provider options detected. Provider will not be loaded', 'provider.middleware.invalid', req.id) @@ -87,7 +91,9 @@ module.exports.getProviderMiddleware = (providers, grantConfig) => { * @returns {Record} */ module.exports.getDefaultProviders = () => { - const providers = { dropbox, box, drive, facebook, onedrive, zoom, instagram, unsplash } + const providers = { + dropbox, box, drive, facebook, onedrive, zoom, instagram, unsplash, webdavOauth, webdavSimpleAuth, + } return providers } diff --git a/packages/@uppy/companion/src/server/provider/webdav/WebdavOauthProvider.js b/packages/@uppy/companion/src/server/provider/webdav/WebdavOauthProvider.js new file mode 100644 index 0000000000..71544223f4 --- /dev/null +++ b/packages/@uppy/companion/src/server/provider/webdav/WebdavOauthProvider.js @@ -0,0 +1,92 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +const { XMLParser } = require('fast-xml-parser') + +const WebdavProvider = require('./common') +const { getProtectedGot, validateURL } = require('../../helpers/request') + +const cloudTypePathMappings = { + nextcloud: { + manual_revoke_url: '/settings/user/security', + }, + owncloud: { + manual_revoke_url: '/settings/personal?sectionid=security', + }, +} + +class WebdavOauth extends WebdavProvider { + constructor (options) { + super(options) + this.authProvider = WebdavOauth.authProvider + } + + // for "grant" + static getExtraConfig () { + return {} + } + + // eslint-disable-next-line class-methods-use-this + static grantDynamicToUserSession ({ grantDynamic }) { + return { + subdomain: grantDynamic.subdomain, + } + } + + static get authProvider () { + return 'webdav' + } + + #getBaseUrl ({ providerUserSession: { subdomain } }) { + const { protocol } = this.providerOptions + + return `${protocol}://${subdomain}` + } + + // eslint-disable-next-line class-methods-use-this + isAuthenticated ({ providerUserSession }) { + return providerUserSession.subdomain != null + } + + async getUsername ({ token, providerUserSession }) { + const { allowLocalUrls } = this + + const url = `${this.#getBaseUrl({ providerUserSession })}/ocs/v1.php/cloud/user` + if (!validateURL(url, allowLocalUrls)) { + throw new Error('invalid user url') + } + + const response = await getProtectedGot({ url, blockLocalIPs: !allowLocalUrls }).get(url, { + headers: { + Authorization: `Bearer ${token}`, + }, + }).text() + + const parser = new XMLParser() + const data = parser.parse(response) + return data?.ocs?.data?.id + } + + async getClient ({ username, token, providerUserSession }) { + const url = `${this.#getBaseUrl({ providerUserSession })}/remote.php/dav/files/${username}` + + const { AuthType } = await import('webdav') // eslint-disable-line import/no-unresolved + return this.getClientHelper({ + url, + authType: AuthType.Token, + token: { + access_token: token, + token_type: 'Bearer', + }, + }) + } + + async logout ({ providerUserSession }) { + const { cloudType } = providerUserSession + const manual_revoke_url = cloudTypePathMappings[cloudType]?.manual_revoke_url + return { + revoked: false, + ...(manual_revoke_url && { manual_revoke_url: `${this.#getBaseUrl({ providerUserSession })}${manual_revoke_url}` }), + } + } +} + +module.exports = WebdavOauth diff --git a/packages/@uppy/companion/src/server/provider/webdav/WebdavSimpleAuthProvider.js b/packages/@uppy/companion/src/server/provider/webdav/WebdavSimpleAuthProvider.js new file mode 100644 index 0000000000..3ff6d6e6e0 --- /dev/null +++ b/packages/@uppy/companion/src/server/provider/webdav/WebdavSimpleAuthProvider.js @@ -0,0 +1,79 @@ +const { validateURL } = require('../../helpers/request') +const WebdavProvider = require('./common') +const { ProviderUserError } = require('../error') +const logger = require('../../logger') + +const defaultDirectory = '/' + +/** + * Adapter for WebDAV servers that support simple auth (non-OAuth). + */ +class WebdavSimpleAuthProvider extends WebdavProvider { + static get hasSimpleAuth () { + return true + } + + async getUsername () { // eslint-disable-line class-methods-use-this + return null + } + + // eslint-disable-next-line class-methods-use-this + isAuthenticated ({ providerUserSession }) { + return providerUserSession.webdavUrl != null + } + + async getClient ({ providerUserSession }) { + const webdavUrl = providerUserSession?.webdavUrl + const { allowLocalUrls } = this + if (!validateURL(webdavUrl, allowLocalUrls)) { + throw new Error('invalid public link url') + } + + const { AuthType } = await import('webdav') // eslint-disable-line import/no-unresolved + + // Is this a nextcloud URL? e.g. https://example.com/s/kFy9Lek5sm928xP + // they have specific urls that we can identify + // todo not sure if this is the right way to support nextcloud and other webdavs + if (/\/s\/([^/]+)/.test(webdavUrl)) { + const [baseURL, publicLinkToken] = webdavUrl.split('/s/') + + return this.getClientHelper({ + url: `${baseURL.replace('/index.php', '')}/public.php/webdav/`, + authType: AuthType.Password, + username: publicLinkToken, + password: 'null', + }) + } + + // normal public WebDAV urls + return this.getClientHelper({ + url: webdavUrl, + authType: AuthType.None, + }) + } + + async logout () { // eslint-disable-line class-methods-use-this + return { revoked: true } + } + + async simpleAuth ({ requestBody }) { + try { + const providerUserSession = { webdavUrl: requestBody.form.webdavUrl } + + const client = await this.getClient({ providerUserSession }) + // call the list operation as a way to validate the url + await client.getDirectoryContents(defaultDirectory) + + return providerUserSession + } catch (err) { + logger.error(err, 'provider.webdav.simpleAuth.error') + if (['ECONNREFUSED', 'ENOTFOUND'].includes(err.code)) { + throw new ProviderUserError({ message: 'Cannot connect to server' }) + } + // todo report back to the user what actually went wrong + throw err + } + } +} + +module.exports = WebdavSimpleAuthProvider diff --git a/packages/@uppy/companion/src/server/provider/webdav/common.js b/packages/@uppy/companion/src/server/provider/webdav/common.js new file mode 100644 index 0000000000..2b2eff52fe --- /dev/null +++ b/packages/@uppy/companion/src/server/provider/webdav/common.js @@ -0,0 +1,123 @@ +const Provider = require('../Provider') +const logger = require('../../logger') +const { getProtectedHttpAgent, validateURL } = require('../../helpers/request') +const { ProviderApiError, ProviderAuthError } = require('../error') + +/** + * WebdavProvider base class provides implementations shared by simple and oauth providers + */ +class WebdavProvider extends Provider { + async getClientHelper ({ url, ...options }) { + const { allowLocalUrls } = this + if (!validateURL(url, allowLocalUrls)) { + throw new Error('invalid webdav url') + } + const { protocol } = new URL(url) + const HttpAgentClass = getProtectedHttpAgent({ protocol, blockLocalIPs: !allowLocalUrls }) + + const { createClient } = await import('webdav') // eslint-disable-line import/no-unresolved + return createClient(url, { + ...options, + [`${protocol}Agent`] : new HttpAgentClass(), + }) + } + + async getClient ({ username, token, providerUserSession }) { // eslint-disable-line no-unused-vars,class-methods-use-this + logger.error('call to getUsername is not implemented', 'provider.webdav.getUsername.error') + throw new Error('call to getUsername is not implemented') + // todo: use @returns to specify the return type + return this.getClientHelper() // eslint-disable-line + } + + async getUsername ({ token, providerUserSession }) { // eslint-disable-line no-unused-vars,class-methods-use-this + logger.error('call to getUsername is not implemented', 'provider.webdav.getUsername.error') + throw new Error('call to getUsername is not implemented') + } + + /** @protected */ + // eslint-disable-next-line class-methods-use-this + isAuthenticated () { + throw new Error('Not implemented') + } + + async list ({ directory, token, providerUserSession }) { + return this.withErrorHandling('provider.webdav.list.error', async () => { + // @ts-ignore + if (!this.isAuthenticated({ providerUserSession })) { + throw new ProviderAuthError() + } + + const username = await this.getUsername({ token, providerUserSession }) + const data = { username, items: [] } + const client = await this.getClient({ username, token, providerUserSession }) + + /** @type {any} */ + const dir = await client.getDirectoryContents(directory || '/') + + dir.forEach(item => { + const isFolder = item.type === 'directory' + const requestPath = encodeURIComponent(`${directory || ''}/${item.basename}`) + data.items.push({ + isFolder, + id: requestPath, + name: item.basename, + requestPath, // TODO FIXME + modifiedDate: item.lastmod, // TODO FIXME: convert 'Tue, 04 Jul 2023 13:09:47 GMT' to ISO 8601 + ...(!isFolder && { + mimeType: item.mime, + size: item.size, + thumbnail: null, + + }), + }) + }) + + return data + }) + } + + async download ({ id, token, providerUserSession }) { + return this.withErrorHandling('provider.webdav.download.error', async () => { + // maybe we can avoid this by putting the username in front of the request path/id + const username = await this.getUsername({ token, providerUserSession }) + const client = await this.getClient({ username, token, providerUserSession }) + const stream = client.createReadStream(`/${id}`) + return { stream } + }) + } + + // eslint-disable-next-line + async thumbnail ({ id, providerUserSession }) { + // not implementing this because a public thumbnail from webdav will be used instead + logger.error('call to thumbnail is not implemented', 'provider.webdav.thumbnail.error') + throw new Error('call to thumbnail is not implemented') + } + + // todo fixme implement + // eslint-disable-next-line + async size ({ id, token, providerUserSession }) { + return this.withErrorHandling('provider.webdav.size.error', async () => { + const username = await this.getUsername({ token, providerUserSession }) + const client = await this.getClient({ username, token, providerUserSession }) + const stat = await client.stat(id) + return stat.size + }) + } + + // eslint-disable-next-line class-methods-use-this + async withErrorHandling (tag, fn) { + try { + return await fn() + } catch (err) { + let err2 = err + if (err.status === 401) err2 = new ProviderAuthError() + if (err.response) { + err2 = new ProviderApiError('WebDAV API error', err.status) // todo improve (read err?.response?.body readable stream and parse response) + } + logger.error(err2, tag) + throw err2 + } + } +} + +module.exports = WebdavProvider diff --git a/packages/@uppy/companion/src/standalone/helper.js b/packages/@uppy/companion/src/standalone/helper.js index 1a77119e16..d934fe05b9 100644 --- a/packages/@uppy/companion/src/standalone/helper.js +++ b/packages/@uppy/companion/src/standalone/helper.js @@ -116,6 +116,12 @@ const getConfigFromEnv = () => { key: process.env.COMPANION_UNSPLASH_KEY, secret: process.env.COMPANION_UNSPLASH_SECRET, }, + webdavOauth: { + key: process.env.COMPANION_WEBDAV_KEY, + secret: getSecret('COMPANION_WEBDAV_SECRET'), + credentialsURL: process.env.COMPANION_WEBDAV_KEYS_ENDPOINT, + protocol: 'https', + }, }, s3: { key: process.env.COMPANION_AWS_KEY, diff --git a/packages/@uppy/webdav/package.json b/packages/@uppy/webdav/package.json new file mode 100644 index 0000000000..d753114830 --- /dev/null +++ b/packages/@uppy/webdav/package.json @@ -0,0 +1,35 @@ +{ + "name": "@uppy/webdav", + "description": "Import files from WebDAV into Uppy.", + "version": "3.1.1", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "type": "module", + "keywords": [ + "file uploader", + "uppy", + "uppy-plugin", + "instagram", + "provider", + "photos", + "videos" + ], + "homepage": "https://uppy.io", + "bugs": { + "url": "https://github.com/transloadit/uppy/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/transloadit/uppy.git" + }, + "dependencies": { + "@uppy/companion-client": "workspace:^", + "@uppy/provider-views": "workspace:^", + "@uppy/utils": "workspace:^", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "workspace:^" + } +} diff --git a/packages/@uppy/webdav/src/WebdavOauth.jsx b/packages/@uppy/webdav/src/WebdavOauth.jsx new file mode 100644 index 0000000000..fb1980b57c --- /dev/null +++ b/packages/@uppy/webdav/src/WebdavOauth.jsx @@ -0,0 +1,100 @@ +import { h } from 'preact' +import { useCallback, useState } from 'preact/hooks' + +import { UIPlugin } from '@uppy/core' +import { Provider } from '@uppy/companion-client' +import { ProviderViews } from '@uppy/provider-views' + +import packageJson from '../package.json' +import locale from './locale.js' + +class WebdavOauthProvider extends Provider { + // eslint-disable-next-line class-methods-use-this + authQuery ({ authFormData }) { + const { webdavUrl } = authFormData + + return { + subdomain: new URL(webdavUrl).host || webdavUrl, + } + } +} + +const AuthForm = ({ loading, i18n, onAuth }) => { + const [webdavUrl, setWebdavUrl] = useState('') + + const onSubmit = useCallback((e) => { + e.preventDefault() + onAuth({ webdavUrl }) + }, [onAuth, webdavUrl]) + + return ( +
+ + {i18n('publicLinkURLDescription')} + + +
+ ) +} + +export default class WebdavOauth extends UIPlugin { + static VERSION = packageJson.version + + constructor (uppy, opts) { + super(uppy, opts) + this.id = this.opts.id || 'webdavOauth' + Provider.initPlugin(this, opts) + + this.defaultLocale = locale + this.i18nInit() + + this.title = this.i18n('pluginNameWebdavOauth') + + this.provider = new WebdavOauthProvider(uppy, { + companionUrl: this.opts.companionUrl, + companionHeaders: this.opts.companionHeaders, + companionKeysParams: this.opts.companionKeysParams, + companionCookiesRule: this.opts.companionCookiesRule, + provider: 'webdavOauth', + pluginId: this.id, + supportsRefreshToken: false, + }) + + this.onFirstRender = this.onFirstRender.bind(this) + this.render = this.render.bind(this) + } + + install () { + this.view = new ProviderViews(this, { + provider: this.provider, + viewType: 'list', + showTitles: true, + showFilter: true, + showBreadcrumbs: true, + renderAuthForm: ({ i18n, loading, onAuth }) => ( + + ), + }) + + const { target } = this.opts + if (target) { + this.mount(target, this) + } + } + + uninstall () { + this.view.tearDown() + this.unmount() + } + + onFirstRender () { + return this.view.getFolder() + } + + render (state) { + return this.view.render(state) + } +} diff --git a/packages/@uppy/webdav/src/WebdavSimpleAuth.jsx b/packages/@uppy/webdav/src/WebdavSimpleAuth.jsx new file mode 100644 index 0000000000..1487fc4798 --- /dev/null +++ b/packages/@uppy/webdav/src/WebdavSimpleAuth.jsx @@ -0,0 +1,100 @@ +import { h } from 'preact' +import { useCallback, useState } from 'preact/hooks' + +import { UIPlugin } from '@uppy/core' +import { Provider } from '@uppy/companion-client' +import { ProviderViews } from '@uppy/provider-views' + +import packageJson from '../package.json' +import locale from './locale.js' + +class WebdavSimpleAuthProvider extends Provider { + async login ({ authFormData, uppyVersions, signal }) { + return this.loginSimpleAuth({ uppyVersions, authFormData, signal }) + } + + async logout () { + this.removeAuthToken() + return { ok: true, revoked: true } + } +} + +const AuthForm = ({ loading, i18n, onAuth }) => { + const [webdavUrl, setWebdavUrl] = useState('') + + const onSubmit = useCallback((e) => { + e.preventDefault() + onAuth({ webdavUrl: webdavUrl.trim() }) + }, [onAuth, webdavUrl]) + + return ( +
+ + {i18n('publicLinkURLDescription')} + + +
+ ) +} + +export default class WebdavSimpleAuth extends UIPlugin { + static VERSION = packageJson.version + + constructor (uppy, opts) { + super(uppy, opts) + this.id = this.opts.id || 'webdavSimpleAuth' + Provider.initPlugin(this, opts) + + this.defaultLocale = locale + this.i18nInit() + + this.title = this.i18n('pluginNameWebdavSimpleAuth') + + this.provider = new WebdavSimpleAuthProvider(uppy, { + companionUrl: this.opts.companionUrl, + companionHeaders: this.opts.companionHeaders, + companionKeysParams: this.opts.companionKeysParams, + companionCookiesRule: this.opts.companionCookiesRule, + provider: 'webdavSimpleAuth', + pluginId: this.id, + supportsRefreshToken: false, + }) + + this.onFirstRender = this.onFirstRender.bind(this) + this.render = this.render.bind(this) + } + + install () { + this.view = new ProviderViews(this, { + provider: this.provider, + viewType: 'list', + showTitles: true, + showFilter: true, + showBreadcrumbs: true, + renderAuthForm: ({ i18n, loading, onAuth }) => ( + + ), + }) + + const { target } = this.opts + if (target) { + this.mount(target, this) + } + } + + uninstall () { + this.view.tearDown() + this.unmount() + } + + onFirstRender () { + return this.view.getFolder() + } + + render (state) { + return this.view.render(state) + } +} diff --git a/packages/@uppy/webdav/src/index.js b/packages/@uppy/webdav/src/index.js new file mode 100644 index 0000000000..d25e8b311c --- /dev/null +++ b/packages/@uppy/webdav/src/index.js @@ -0,0 +1,2 @@ +export { default as WebdavOauth } from './WebdavOauth.jsx' +export { default as WebdavSimpleAuth } from './WebdavSimpleAuth.jsx' diff --git a/packages/@uppy/webdav/src/locale.js b/packages/@uppy/webdav/src/locale.js new file mode 100644 index 0000000000..f0f391cbf8 --- /dev/null +++ b/packages/@uppy/webdav/src/locale.js @@ -0,0 +1,4 @@ +export default { + strings: { + }, +} diff --git a/packages/uppy/package.json b/packages/uppy/package.json index 53d79f317c..721b9e2e04 100644 --- a/packages/uppy/package.json +++ b/packages/uppy/package.json @@ -65,6 +65,7 @@ "@uppy/unsplash": "workspace:^", "@uppy/url": "workspace:^", "@uppy/webcam": "workspace:^", + "@uppy/webdav": "workspace:^", "@uppy/xhr-upload": "workspace:^", "@uppy/zoom": "workspace:^" }, diff --git a/private/dev/Dashboard.js b/private/dev/Dashboard.js index 6b20714a98..45dd2ae295 100644 --- a/private/dev/Dashboard.js +++ b/private/dev/Dashboard.js @@ -18,6 +18,8 @@ import Audio from '@uppy/audio' import Compressor from '@uppy/compressor' import GoogleDrive from '@uppy/google-drive' /* eslint-enable import/no-extraneous-dependencies */ +// eslint-disable-next-line import/no-extraneous-dependencies +import { WebdavOauth, WebdavSimpleAuth } from '@uppy/webdav' import generateSignatureIfSecret from './generateSignatureIfSecret.js' @@ -102,6 +104,8 @@ export default () => { proudlyDisplayPoweredByUppy: true, note: `${JSON.stringify(restrictions)}`, }) + .use(WebdavSimpleAuth, { target: Dashboard, companionUrl: COMPANION_URL, companionAllowedHosts }) + .use(WebdavOauth, { target: Dashboard, companionUrl: COMPANION_URL, companionAllowedHosts }) .use(GoogleDrive, { target: Dashboard, companionUrl: COMPANION_URL, companionAllowedHosts, ...getCompanionKeysParams('GOOGLE_DRIVE') }) // .use(Instagram, { target: Dashboard, companionUrl: COMPANION_URL, companionAllowedHosts }) // .use(Dropbox, { target: Dashboard, companionUrl: COMPANION_URL, companionAllowedHosts }) diff --git a/yarn.lock b/yarn.lock index 9fad2fe6c2..9e21bab3ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4134,6 +4134,18 @@ __metadata: languageName: node linkType: hard +"@buttercup/fetch@npm:^0.1.1": + version: 0.1.2 + resolution: "@buttercup/fetch@npm:0.1.2" + dependencies: + node-fetch: ^3.3.0 + dependenciesMeta: + node-fetch: + optional: true + checksum: 005ed59a4189183d4ad17c97ccb3558c0d9e2d89411f7d1c4387df7c2a68a0fde889c973e1518ce14f7456306d0bbaeb9e4624b736f578439c5384197c3f4963 + languageName: node + linkType: hard + "@cnakazawa/watch@npm:^1.0.3": version: 1.0.4 resolution: "@cnakazawa/watch@npm:1.0.4" @@ -9338,6 +9350,7 @@ __metadata: express-prom-bundle: 6.5.0 express-request-id: 1.4.1 express-session: 1.17.3 + fast-xml-parser: ^4.2.7 form-data: ^3.0.0 got: 11 grant: 5.4.21 @@ -9362,6 +9375,7 @@ __metadata: tus-js-client: ^3.0.0 typescript: ~5.1 validator: ^13.0.0 + webdav: ^5.3.0 ws: 8.8.1 bin: companion: ./bin/companion @@ -9860,6 +9874,19 @@ __metadata: languageName: unknown linkType: soft +"@uppy/webdav@workspace:^, @uppy/webdav@workspace:packages/@uppy/webdav": + version: 0.0.0-use.local + resolution: "@uppy/webdav@workspace:packages/@uppy/webdav" + dependencies: + "@uppy/companion-client": "workspace:^" + "@uppy/provider-views": "workspace:^" + "@uppy/utils": "workspace:^" + preact: ^10.5.13 + peerDependencies: + "@uppy/core": "workspace:^" + languageName: unknown + linkType: soft + "@uppy/xhr-upload@workspace:*, @uppy/xhr-upload@workspace:^, @uppy/xhr-upload@workspace:packages/@uppy/xhr-upload": version: 0.0.0-use.local resolution: "@uppy/xhr-upload@workspace:packages/@uppy/xhr-upload" @@ -11694,6 +11721,13 @@ __metadata: languageName: node linkType: hard +"base-64@npm:^1.0.0": + version: 1.0.0 + resolution: "base-64@npm:1.0.0" + checksum: d10b64a1fc9b2c5a5f39f1ce1e6c9d1c5b249222bbfa3a0604c592d90623caf74419983feadd8a170f27dc0c3389704f72faafa3e645aeb56bfc030c93ff074a + languageName: node + linkType: hard + "base-x@npm:^3.0.8": version: 3.0.9 resolution: "base-x@npm:3.0.9" @@ -12111,6 +12145,13 @@ __metadata: languageName: node linkType: hard +"byte-length@npm:^1.0.2": + version: 1.0.2 + resolution: "byte-length@npm:1.0.2" + checksum: 69e2b00a14a81f675ea9946135c42ee1a1d9f689d5ba1327eb6700fcde2ccacbd09b42f7e514de1d2b763960251d8c790b3d7304a5a1a27b1457e34c129be8c7 + languageName: node + linkType: hard + "bytes@npm:3.0.0": version: 3.0.0 resolution: "bytes@npm:3.0.0" @@ -12454,10 +12495,19 @@ __metadata: languageName: node linkType: hard +"charenc@npm:0.0.2": + version: 0.0.2 + resolution: "charenc@npm:0.0.2" + checksum: 81dcadbe57e861d527faf6dd3855dc857395a1c4d6781f4847288ab23cffb7b3ee80d57c15bba7252ffe3e5e8019db767757ee7975663ad2ca0939bb8fcaf2e5 + languageName: node + linkType: hard + "check-error@npm:^1.0.2": - version: 1.0.2 - resolution: "check-error@npm:1.0.2" - checksum: d9d106504404b8addd1ee3f63f8c0eaa7cd962a1a28eb9c519b1c4a1dc7098be38007fc0060f045ee00f075fbb7a2a4f42abcf61d68323677e11ab98dc16042e + version: 1.0.3 + resolution: "check-error@npm:1.0.3" + dependencies: + get-func-name: ^2.0.2 + checksum: e2131025cf059b21080f4813e55b3c480419256914601750b0fee3bd9b2b8315b531e551ef12560419b8b6d92a3636511322752b1ce905703239e7cc451b6399 languageName: node linkType: hard @@ -13389,6 +13439,13 @@ __metadata: languageName: node linkType: hard +"crypt@npm:0.0.2": + version: 0.0.2 + resolution: "crypt@npm:0.0.2" + checksum: baf4c7bbe05df656ec230018af8cf7dbe8c14b36b98726939cef008d473f6fe7a4fad906cfea4062c93af516f1550a3f43ceb4d6615329612c6511378ed9fe34 + languageName: node + linkType: hard + "css-declaration-sorter@npm:^6.3.0": version: 6.3.0 resolution: "css-declaration-sorter@npm:6.3.0" @@ -16497,6 +16554,17 @@ __metadata: languageName: node linkType: hard +"fast-xml-parser@npm:^4.2.4, fast-xml-parser@npm:^4.2.7": + version: 4.2.7 + resolution: "fast-xml-parser@npm:4.2.7" + dependencies: + strnum: ^1.0.5 + bin: + fxparser: src/cli/cli.js + checksum: d8b0c9e04756f6c43fa0399428f30149acadae21350e42e26e8fe98e24e6afa6b9b00aa554453795036b00e9fee974a1b556fe2ba18be391d51a9bf1ab790e7c + languageName: node + linkType: hard + "fastest-levenshtein@npm:^1.0.16": version: 1.0.16 resolution: "fastest-levenshtein@npm:1.0.16" @@ -17243,7 +17311,7 @@ __metadata: languageName: node linkType: hard -"get-func-name@npm:^2.0.0": +"get-func-name@npm:^2.0.0, get-func-name@npm:^2.0.2": version: 2.0.2 resolution: "get-func-name@npm:2.0.2" checksum: 3f62f4c23647de9d46e6f76d2b3eafe58933a9b3830c60669e4180d6c601ce1b4aa310ba8366143f55e52b139f992087a9f0647274e8745621fa2af7e0acf13b @@ -17933,6 +18001,13 @@ __metadata: languageName: node linkType: hard +"hot-patcher@npm:^2.0.0": + version: 2.0.1 + resolution: "hot-patcher@npm:2.0.1" + checksum: 1f30c5d59ba6dcb2b81485d492dbee9520ac262b1502ed1eeca44a52d92f48f8ebc1055a5e462db344a91f834f7cf19d69a2327158b68be7b4858145a0fc8f83 + languageName: node + linkType: hard + "hpack.js@npm:^2.1.6": version: 2.1.6 resolution: "hpack.js@npm:2.1.6" @@ -18683,7 +18758,7 @@ __metadata: languageName: node linkType: hard -"is-buffer@npm:^1.1.5": +"is-buffer@npm:^1.1.5, is-buffer@npm:~1.1.6": version: 1.1.6 resolution: "is-buffer@npm:1.1.6" checksum: 4a186d995d8bbf9153b4bd9ff9fd04ae75068fe695d29025d25e592d9488911eeece84eefbd8fa41b8ddcc0711058a71d4c466dcf6f1f6e1d83830052d8ca707 @@ -20668,6 +20743,13 @@ __metadata: languageName: node linkType: hard +"layerr@npm:^2.0.1": + version: 2.0.1 + resolution: "layerr@npm:2.0.1" + checksum: a57b0ceff240b4869571b0b87c0bc28dc71b131a652c6da5fee03d6f590581c5a57f794edb2ec5ee7c8f7030bf99a4e090516efbd92a2e7382336d60a3d10763 + languageName: node + linkType: hard + "lazy-ass@npm:1.6.0, lazy-ass@npm:^1.6.0": version: 1.6.0 resolution: "lazy-ass@npm:1.6.0" @@ -21696,6 +21778,17 @@ __metadata: languageName: node linkType: hard +"md5@npm:^2.3.0": + version: 2.3.0 + resolution: "md5@npm:2.3.0" + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: ~1.1.6 + checksum: a63cacf4018dc9dee08c36e6f924a64ced735b37826116c905717c41cebeb41a522f7a526ba6ad578f9c80f02cb365033ccd67fe186ffbcc1a1faeb75daa9b6e + languageName: node + linkType: hard + "mdast-comment-marker@npm:^2.0.0, mdast-comment-marker@npm:^2.1.0": version: 2.1.0 resolution: "mdast-comment-marker@npm:2.1.0" @@ -22805,6 +22898,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^7.4.6": + version: 7.4.6 + resolution: "minimatch@npm:7.4.6" + dependencies: + brace-expansion: ^2.0.1 + checksum: 1a6c8d22618df9d2a88aabeef1de5622eb7b558e9f8010be791cb6b0fa6e102d39b11c28d75b855a1e377b12edc7db8ff12a99c20353441caa6a05e78deb5da9 + languageName: node + linkType: hard + "minimatch@npm:^9.0.0, minimatch@npm:^9.0.1": version: 9.0.3 resolution: "minimatch@npm:9.0.3" @@ -23307,6 +23409,13 @@ __metadata: languageName: node linkType: hard +"nested-property@npm:^4.0.0": + version: 4.0.0 + resolution: "nested-property@npm:4.0.0" + checksum: 9c86f2c722429e167876d5becf276139a6aa4b8732b6d9e32de9aa44dfd017702b60614cc87aec961dea47ae50dae0951d5b5f66fc30288f18bf581c16e42ca2 + languageName: node + linkType: hard + "ng-packagr@npm:^16.2.0": version: 16.2.0 resolution: "ng-packagr@npm:16.2.0" @@ -23518,6 +23627,17 @@ __metadata: languageName: node linkType: hard +"node-fetch@npm:^3.3.0": + version: 3.3.2 + resolution: "node-fetch@npm:3.3.2" + dependencies: + data-uri-to-buffer: ^4.0.0 + fetch-blob: ^3.1.4 + formdata-polyfill: ^4.0.10 + checksum: 06a04095a2ddf05b0830a0d5302699704d59bda3102894ea64c7b9d4c865ecdff2d90fd042df7f5bc40337266961cb6183dcc808ea4f3000d024f422b462da92 + languageName: node + linkType: hard + "node-forge@npm:^1": version: 1.3.1 resolution: "node-forge@npm:1.3.1" @@ -24968,6 +25088,13 @@ __metadata: languageName: node linkType: hard +"path-posix@npm:^1.0.0": + version: 1.0.0 + resolution: "path-posix@npm:1.0.0" + checksum: 4f64ad212de6ad8d0dbfa440cac8b924303c25c30301769ad0501e29e83a5b9d469e8133753f999ad37482c9c8d3511129e4d83db55d2e4b1555b183c9749ae8 + languageName: node + linkType: hard + "path-scurry@npm:^1.10.1": version: 1.10.1 resolution: "path-scurry@npm:1.10.1" @@ -31076,6 +31203,7 @@ __metadata: "@uppy/unsplash": "workspace:^" "@uppy/url": "workspace:^" "@uppy/webcam": "workspace:^" + "@uppy/webdav": "workspace:^" "@uppy/xhr-upload": "workspace:^" "@uppy/zoom": "workspace:^" abortcontroller-polyfill: ^1.7.3 @@ -31103,7 +31231,14 @@ __metadata: languageName: node linkType: hard -"url-parse@npm:^1.4.4, url-parse@npm:^1.5.3, url-parse@npm:^1.5.7": +"url-join@npm:^5.0.0": + version: 5.0.0 + resolution: "url-join@npm:5.0.0" + checksum: 5921384a8ad4395b49ce4b50aa26efbc429cebe0bc8b3660ad693dd12fd859747b5369be0443e60e53a7850b2bc9d7d0687bcb94386662b40e743596bbf38101 + languageName: node + linkType: hard + +"url-parse@npm:^1.4.4, url-parse@npm:^1.5.10, url-parse@npm:^1.5.3, url-parse@npm:^1.5.7": version: 1.5.10 resolution: "url-parse@npm:1.5.10" dependencies: @@ -31798,6 +31933,27 @@ __metadata: languageName: node linkType: hard +"webdav@npm:^5.3.0": + version: 5.3.0 + resolution: "webdav@npm:5.3.0" + dependencies: + "@buttercup/fetch": ^0.1.1 + base-64: ^1.0.0 + byte-length: ^1.0.2 + fast-xml-parser: ^4.2.4 + he: ^1.2.0 + hot-patcher: ^2.0.0 + layerr: ^2.0.1 + md5: ^2.3.0 + minimatch: ^7.4.6 + nested-property: ^4.0.0 + path-posix: ^1.0.0 + url-join: ^5.0.0 + url-parse: ^1.5.10 + checksum: 66f85e181c7d51f0ce0a55f4aed6f0347b73b3e1a4dd2e3312c39a4d966f71135423247e11ff7d4991074c16a7fb2ab30577774849edfd529a2cc9354c413114 + languageName: node + linkType: hard + "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1"