mirror of
https://github.com/transloadit/uppy.git
synced 2026-07-17 16:50:22 +00:00
@uppy/companion: fix (breaking) todo comments (#5802)
This commit is contained in:
parent
0294539af6
commit
06ddd99cd1
27 changed files with 112 additions and 162 deletions
|
|
@ -1,4 +1,3 @@
|
|||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import deepFreeze from 'deep-freeze'
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ class MyCustomProvider {
|
|||
return 'myunsplash'
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
async list({ token, directory }) {
|
||||
const path = directory ? `/${directory}/photos` : ''
|
||||
|
||||
|
|
@ -55,7 +54,6 @@ class MyCustomProvider {
|
|||
return adaptData(await resp.json())
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
async download({ id, token }) {
|
||||
const resp = await fetch(`${BASE_URL}/photos/${id}`, {
|
||||
headers: {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ const upload = multer({
|
|||
function uploadRoute(req, res) {
|
||||
res.json({
|
||||
files: req.files.map((file) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
delete file.buffer
|
||||
return file
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -36,13 +36,14 @@ describe('isOriginAllowed', () => {
|
|||
expect(isOriginAllowed('a', [/^.+$/])).toBeTruthy()
|
||||
expect(isOriginAllowed('a', ['^.+$'])).toBeTruthy()
|
||||
expect(
|
||||
isOriginAllowed('www.transloadit.com', ['www\\.transloadit\\.com']),
|
||||
isOriginAllowed('www.transloadit.com', ['^www\\.transloadit\\.com$']),
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
isOriginAllowed('www.transloadit.com', ['transloadit\\.com']),
|
||||
isOriginAllowed('www.transloadit.com', ['^transloadit\\.com$']),
|
||||
).toBeFalsy()
|
||||
expect(isOriginAllowed('match', ['fail', 'match'])).toBeTruthy()
|
||||
// todo maybe next major:
|
||||
// expect(isOriginAllowed('www.transloadit.com', ['\\.transloadit\\.com$'])).toBeTruthy()
|
||||
expect(
|
||||
isOriginAllowed('www.transloadit.com', ['\\.transloadit\\.com$']),
|
||||
).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ function escapeRegex(string: string) {
|
|||
|
||||
function wrapInRegex(value?: string | RegExp): RegExp | undefined {
|
||||
if (typeof value === 'string') {
|
||||
// TODO in the next major we should change this to `new RegExp(value)` so that the user can control start/end characters
|
||||
return new RegExp(`^${value}$`) // throws if invalid regex
|
||||
return new RegExp(value) // throws if invalid regex
|
||||
}
|
||||
if (value instanceof RegExp) {
|
||||
return value
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ function validateOptions(options) {
|
|||
}
|
||||
|
||||
// validate protocol
|
||||
// @todo this validation should not be conditional once the protocol field is mandatory
|
||||
if (
|
||||
options.protocol &&
|
||||
!Object.keys(PROTOCOLS).some((key) => PROTOCOLS[key] === options.protocol)
|
||||
|
|
@ -227,8 +226,6 @@ class Uploader {
|
|||
}
|
||||
|
||||
_getUploadProtocol() {
|
||||
// todo a default protocol should not be set. We should ensure that the user specifies their protocol.
|
||||
// after we drop old versions of uppy client we can remove this
|
||||
return this.options.protocol || PROTOCOLS.multipart
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,25 +5,14 @@ const { respondWithError } = require('../provider/error')
|
|||
async function get(req, res) {
|
||||
const { id } = req.params
|
||||
const { providerUserSession } = req.companion
|
||||
const { accessToken } = providerUserSession
|
||||
const { provider } = req.companion
|
||||
|
||||
async function getSize() {
|
||||
return provider.size({
|
||||
id,
|
||||
token: accessToken,
|
||||
providerUserSession,
|
||||
query: req.query,
|
||||
})
|
||||
return provider.size({ id, providerUserSession, query: req.query })
|
||||
}
|
||||
|
||||
const download = () =>
|
||||
provider.download({
|
||||
id,
|
||||
token: accessToken,
|
||||
providerUserSession,
|
||||
query: req.query,
|
||||
})
|
||||
provider.download({ id, providerUserSession, query: req.query })
|
||||
|
||||
try {
|
||||
await startDownUpload({ req, res, getSize, download })
|
||||
|
|
|
|||
|
|
@ -2,13 +2,10 @@ const { respondWithError } = require('../provider/error')
|
|||
|
||||
async function list({ query, params, companion }, res, next) {
|
||||
const { providerUserSession } = companion
|
||||
const { accessToken } = providerUserSession
|
||||
|
||||
try {
|
||||
// todo remove backward compat `token` param from all provider methods (because it can be found in providerUserSession)
|
||||
const data = await companion.provider.list({
|
||||
companion,
|
||||
token: accessToken,
|
||||
providerUserSession,
|
||||
directory: params.id,
|
||||
query,
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ async function logout(req, res, next) {
|
|||
}
|
||||
|
||||
try {
|
||||
const { accessToken } = providerUserSession
|
||||
const data = await companion.provider.logout({
|
||||
token: accessToken,
|
||||
providerUserSession,
|
||||
companion,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -8,12 +8,10 @@ const { respondWithError } = require('../provider/error')
|
|||
async function thumbnail(req, res, next) {
|
||||
const { id } = req.params
|
||||
const { provider, providerUserSession } = req.companion
|
||||
const { accessToken } = providerUserSession
|
||||
|
||||
try {
|
||||
const { stream, contentType } = await provider.thumbnail({
|
||||
id,
|
||||
token: accessToken,
|
||||
providerUserSession,
|
||||
})
|
||||
if (contentType != null) res.set('Content-Type', contentType)
|
||||
|
|
|
|||
|
|
@ -181,8 +181,6 @@ exports.getURLMeta = async (
|
|||
}
|
||||
|
||||
if (urlMeta.statusCode >= 300) {
|
||||
// @todo possibly set a status code in the error object to get a more helpful
|
||||
// hint at what the cause of error is.
|
||||
throw new Error(`URL server responded with status: ${urlMeta.statusCode}`)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
const crypto = require('node:crypto')
|
||||
const logger = require('../logger.js')
|
||||
|
||||
const authTagLength = 16
|
||||
const nonceLength = 16
|
||||
|
|
@ -120,43 +119,6 @@ module.exports.encrypt = (input, secret) => {
|
|||
return `${nonce.toString('hex')}${encrypted.toString('base64url')}`
|
||||
}
|
||||
|
||||
// todo backwards compat for old tokens - remove in the future
|
||||
function compatDecrypt(encrypted, secret) {
|
||||
// Need at least 32 chars for the iv
|
||||
if (encrypted.length < 32) {
|
||||
throw new Error(
|
||||
'Invalid encrypted value. Maybe it was generated with an old Companion version?',
|
||||
)
|
||||
}
|
||||
|
||||
// NOTE: The first 32 characters are the iv, in hex format. The rest is the encrypted string, in base64 format.
|
||||
const iv = Buffer.from(encrypted.slice(0, 32), 'hex')
|
||||
const encryptionWithoutIv = encrypted.slice(32)
|
||||
|
||||
let decipher
|
||||
try {
|
||||
const secretHashed = crypto.createHash('sha256')
|
||||
secretHashed.update(secret)
|
||||
decipher = crypto.createDecipheriv('aes256', secretHashed.digest(), iv)
|
||||
} catch (err) {
|
||||
if (err.code === 'ERR_CRYPTO_INVALID_IV') {
|
||||
throw new Error('Invalid initialization vector')
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
const urlDecode = (encoded) =>
|
||||
encoded.replace(/-/g, '+').replace(/_/g, '/').replace(/~/g, '=')
|
||||
let decrypted = decipher.update(
|
||||
urlDecode(encryptionWithoutIv),
|
||||
'base64',
|
||||
'utf8',
|
||||
)
|
||||
decrypted += decipher.final('utf8')
|
||||
return decrypted
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt an iv-prefixed or string with AES256. The iv should be in the first 32 hex characters.
|
||||
*
|
||||
|
|
@ -165,47 +127,41 @@ function compatDecrypt(encrypted, secret) {
|
|||
* @returns {string} Decrypted value.
|
||||
*/
|
||||
module.exports.decrypt = (encrypted, secret) => {
|
||||
try {
|
||||
const nonceHexLength = nonceLength * 2 // because hex encoding uses 2 bytes per byte
|
||||
const nonceHexLength = nonceLength * 2 // because hex encoding uses 2 bytes per byte
|
||||
|
||||
// NOTE: The first 32 characters are the nonce, in hex format.
|
||||
const nonce = Buffer.from(encrypted.slice(0, nonceHexLength), 'hex')
|
||||
// The rest is the encrypted string, in base64url format.
|
||||
const encryptionWithoutNonce = Buffer.from(
|
||||
encrypted.slice(nonceHexLength),
|
||||
'base64url',
|
||||
// NOTE: The first 32 characters are the nonce, in hex format.
|
||||
const nonce = Buffer.from(encrypted.slice(0, nonceHexLength), 'hex')
|
||||
// The rest is the encrypted string, in base64url format.
|
||||
const encryptionWithoutNonce = Buffer.from(
|
||||
encrypted.slice(nonceHexLength),
|
||||
'base64url',
|
||||
)
|
||||
// The last 16 bytes of the rest is the authentication tag
|
||||
const authTag = encryptionWithoutNonce.subarray(-authTagLength)
|
||||
// and the rest (from beginning) is the encrypted data
|
||||
const encryptionWithoutNonceAndTag = encryptionWithoutNonce.subarray(
|
||||
0,
|
||||
-authTagLength,
|
||||
)
|
||||
|
||||
if (nonce.length < nonceLength) {
|
||||
throw new Error(
|
||||
'Invalid encrypted value. Maybe it was generated with an old Companion version?',
|
||||
)
|
||||
// The last 16 bytes of the rest is the authentication tag
|
||||
const authTag = encryptionWithoutNonce.subarray(-authTagLength)
|
||||
// and the rest (from beginning) is the encrypted data
|
||||
const encryptionWithoutNonceAndTag = encryptionWithoutNonce.subarray(
|
||||
0,
|
||||
-authTagLength,
|
||||
)
|
||||
|
||||
if (nonce.length < nonceLength) {
|
||||
throw new Error(
|
||||
'Invalid encrypted value. Maybe it was generated with an old Companion version?',
|
||||
)
|
||||
}
|
||||
|
||||
const { key, iv } = createSecrets(secret, nonce)
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes-256-ccm', key, iv, {
|
||||
authTagLength,
|
||||
})
|
||||
decipher.setAuthTag(authTag)
|
||||
|
||||
const decrypted = Buffer.concat([
|
||||
decipher.update(encryptionWithoutNonceAndTag),
|
||||
decipher.final(),
|
||||
])
|
||||
return decrypted.toString('utf8')
|
||||
} catch (err) {
|
||||
// todo backwards compat for old tokens - remove in the future
|
||||
logger.info('Failed to decrypt - trying old encryption format instead', err)
|
||||
return compatDecrypt(encrypted, secret)
|
||||
}
|
||||
|
||||
const { key, iv } = createSecrets(secret, nonce)
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes-256-ccm', key, iv, {
|
||||
authTagLength,
|
||||
})
|
||||
decipher.setAuthTag(authTag)
|
||||
|
||||
const decrypted = Buffer.concat([
|
||||
decipher.update(encryptionWithoutNonceAndTag),
|
||||
decipher.final(),
|
||||
])
|
||||
return decrypted.toString('utf8')
|
||||
}
|
||||
|
||||
module.exports.defaultGetKey = ({ filename }) => {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ class Provider {
|
|||
* @returns {Promise}
|
||||
*/
|
||||
async deauthorizationCallback(options) {
|
||||
// @todo consider doing something like throw new NotImplementedError() instead
|
||||
throw new Error('method not implemented')
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,10 +56,15 @@ class Box extends Provider {
|
|||
* @param {object} options
|
||||
* @param {string} options.directory
|
||||
* @param {any} options.query
|
||||
* @param {string} options.token
|
||||
* @param {{ accessToken: string }} options.providerUserSession
|
||||
* @param {unknown} options.companion
|
||||
*/
|
||||
async list({ directory, token, query, companion }) {
|
||||
async list({
|
||||
directory,
|
||||
providerUserSession: { accessToken: token },
|
||||
query,
|
||||
companion,
|
||||
}) {
|
||||
return this.#withErrorHandling('provider.box.list.error', async () => {
|
||||
const [userInfo, files] = await Promise.all([
|
||||
getUserInfo({ token }),
|
||||
|
|
@ -70,7 +75,7 @@ class Box extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
async download({ id, token }) {
|
||||
async download({ id, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling('provider.box.download.error', async () => {
|
||||
const stream = (await getClient({ token })).stream.get(
|
||||
`files/${id}/content`,
|
||||
|
|
@ -82,7 +87,7 @@ class Box extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
async thumbnail({ id, token }) {
|
||||
async thumbnail({ id, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling('provider.box.thumbnail.error', async () => {
|
||||
const extension = 'jpg' // you can set this to png to more easily reproduce http 202 retry-after
|
||||
|
||||
|
|
@ -111,7 +116,7 @@ class Box extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
async size({ id, token }) {
|
||||
async size({ id, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling('provider.box.size.error', async () => {
|
||||
const { size } = await (await getClient({ token }))
|
||||
.get(`files/${id}`, { responseType: 'json' })
|
||||
|
|
@ -120,7 +125,7 @@ class Box extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
logout({ companion, token }) {
|
||||
logout({ companion, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling('provider.box.logout.error', async () => {
|
||||
const { key, secret } = companion.options.providerOptions.box
|
||||
await (await getClient({ token })).post('oauth2/revoke', {
|
||||
|
|
|
|||
|
|
@ -187,8 +187,6 @@ exports.getCredentialsOverrideMiddleware = (providers, companionOptions) => {
|
|||
|
||||
next()
|
||||
} catch (keyErr) {
|
||||
// TODO we should return an html page here that can communicate the error
|
||||
// back to the Uppy client, just like /send-token does
|
||||
res.send(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ class DropBox extends Provider {
|
|||
async list(options) {
|
||||
return this.#withErrorHandling('provider.dropbox.list.error', async () => {
|
||||
const { client, userInfo } = await getClient({
|
||||
token: options.token,
|
||||
token: options.providerUserSession.accessToken,
|
||||
namespaced: true,
|
||||
})
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ class DropBox extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
async download({ id, token }) {
|
||||
async download({ id, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling(
|
||||
'provider.dropbox.download.error',
|
||||
async () => {
|
||||
|
|
@ -155,7 +155,7 @@ class DropBox extends Provider {
|
|||
)
|
||||
}
|
||||
|
||||
async thumbnail({ id, token }) {
|
||||
async thumbnail({ id, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling(
|
||||
'provider.dropbox.thumbnail.error',
|
||||
async () => {
|
||||
|
|
@ -180,7 +180,7 @@ class DropBox extends Provider {
|
|||
)
|
||||
}
|
||||
|
||||
async size({ id, token }) {
|
||||
async size({ id, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling('provider.dropbox.size.error', async () => {
|
||||
const { size } = await (
|
||||
await getClient({ token, namespaced: true })
|
||||
|
|
@ -194,7 +194,7 @@ class DropBox extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
async logout({ token }) {
|
||||
async logout({ providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling(
|
||||
'provider.dropbox.logout.error',
|
||||
async () => {
|
||||
|
|
|
|||
|
|
@ -70,7 +70,11 @@ class Facebook extends Provider {
|
|||
return 'facebook'
|
||||
}
|
||||
|
||||
async list({ directory, token, query = { cursor: null } }) {
|
||||
async list({
|
||||
directory,
|
||||
providerUserSession: { accessToken: token },
|
||||
query = { cursor: null },
|
||||
}) {
|
||||
return this.#withErrorHandling('provider.facebook.list.error', async () => {
|
||||
const qs = { fields: 'name,cover_photo,created_time,type' }
|
||||
|
||||
|
|
@ -100,7 +104,7 @@ class Facebook extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
async download({ id, token }) {
|
||||
async download({ id, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling(
|
||||
'provider.facebook.download.error',
|
||||
async () => {
|
||||
|
|
@ -121,7 +125,7 @@ class Facebook extends Provider {
|
|||
throw new Error('call to thumbnail is not implemented')
|
||||
}
|
||||
|
||||
async logout({ token }) {
|
||||
async logout({ providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling(
|
||||
'provider.facebook.logout.error',
|
||||
async () => {
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@ class Drive extends Provider {
|
|||
async () => {
|
||||
const directory = options.directory || 'root'
|
||||
const query = options.query || {}
|
||||
const { token } = options
|
||||
const {
|
||||
providerUserSession: { accessToken: token },
|
||||
} = options
|
||||
|
||||
const isRoot = directory === 'root'
|
||||
const isVirtualSharedDirRoot = directory === VIRTUAL_SHARED_DIR
|
||||
|
|
@ -204,7 +206,7 @@ class Drive extends Provider {
|
|||
)
|
||||
}
|
||||
|
||||
async download({ id, token }) {
|
||||
async download({ id, providerUserSession: { accessToken: token } }) {
|
||||
if (mockAccessTokenExpiredError != null) {
|
||||
logger.warn(`Access token: ${token}`)
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ async function refreshToken({
|
|||
)
|
||||
}
|
||||
|
||||
async function logout({ token }) {
|
||||
async function logout({ providerUserSession: { accessToken: token } }) {
|
||||
return withGoogleErrorHandling(
|
||||
'google',
|
||||
'provider.google.logout.error',
|
||||
|
|
|
|||
|
|
@ -40,7 +40,11 @@ class Instagram extends Provider {
|
|||
return 'instagram'
|
||||
}
|
||||
|
||||
async list({ directory, token, query = { cursor: null } }) {
|
||||
async list({
|
||||
directory,
|
||||
providerUserSession: { accessToken: token },
|
||||
query = { cursor: null },
|
||||
}) {
|
||||
return this.#withErrorHandling(
|
||||
'provider.instagram.list.error',
|
||||
async () => {
|
||||
|
|
@ -69,7 +73,7 @@ class Instagram extends Provider {
|
|||
)
|
||||
}
|
||||
|
||||
async download({ id, token }) {
|
||||
async download({ id, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling(
|
||||
'provider.instagram.download.error',
|
||||
async () => {
|
||||
|
|
|
|||
|
|
@ -37,9 +37,13 @@ class OneDrive extends Provider {
|
|||
* @param {object} options
|
||||
* @param {string} options.directory
|
||||
* @param {any} options.query
|
||||
* @param {string} options.token
|
||||
* @param {{ accessToken: string }} options.providerUserSession
|
||||
*/
|
||||
async list({ directory, query, token }) {
|
||||
async list({
|
||||
directory,
|
||||
query,
|
||||
providerUserSession: { accessToken: token },
|
||||
}) {
|
||||
return this.#withErrorHandling('provider.onedrive.list.error', async () => {
|
||||
const path = directory ? `items/${directory}` : 'root'
|
||||
// https://learn.microsoft.com/en-us/graph/query-parameters?tabs=http#top-parameter
|
||||
|
|
@ -66,7 +70,7 @@ class OneDrive extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
async download({ id, token, query }) {
|
||||
async download({ id, providerUserSession: { accessToken: token }, query }) {
|
||||
return this.#withErrorHandling(
|
||||
'provider.onedrive.download.error',
|
||||
async () => {
|
||||
|
|
@ -89,7 +93,7 @@ class OneDrive extends Provider {
|
|||
throw new Error('call to thumbnail is not implemented')
|
||||
}
|
||||
|
||||
async size({ id, query, token }) {
|
||||
async size({ id, query, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling('provider.onedrive.size.error', async () => {
|
||||
const { size } = await (await getClient({ token }))
|
||||
.get(`${getRootPath(query)}/items/${id}`, { responseType: 'json' })
|
||||
|
|
|
|||
|
|
@ -23,7 +23,10 @@ const getPhotoMeta = async (client, id) =>
|
|||
* Adapter for API https://api.unsplash.com
|
||||
*/
|
||||
class Unsplash extends Provider {
|
||||
async list({ token, query = { cursor: null, q: null } }) {
|
||||
async list({
|
||||
providerUserSession: { accessToken: token },
|
||||
query = { cursor: null, q: null },
|
||||
}) {
|
||||
if (typeof query.q !== 'string') {
|
||||
throw new ProviderApiError('Search query missing', 400)
|
||||
}
|
||||
|
|
@ -39,7 +42,7 @@ class Unsplash extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
async download({ id, token }) {
|
||||
async download({ id, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling(
|
||||
'provider.unsplash.download.error',
|
||||
async () => {
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ class WebdavProvider extends Provider {
|
|||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -168,7 +167,7 @@ class WebdavProvider extends Provider {
|
|||
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)
|
||||
err2 = new ProviderApiError('WebDAV API error', err.status)
|
||||
}
|
||||
logger.error(err2, tag)
|
||||
throw err2
|
||||
|
|
|
|||
|
|
@ -45,7 +45,9 @@ class Zoom extends Provider {
|
|||
|
||||
async list(options) {
|
||||
return this.#withErrorHandling('provider.zoom.list.error', async () => {
|
||||
const { token } = options
|
||||
const {
|
||||
providerUserSession: { accessToken: token },
|
||||
} = options
|
||||
const query = options.query || {}
|
||||
const meetingId = options.directory || ''
|
||||
const requestedYear = query.year ? parseInt(query.year, 10) : null
|
||||
|
|
@ -141,7 +143,11 @@ class Zoom extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
async download({ id: meetingId, token, query }) {
|
||||
async download({
|
||||
id: meetingId,
|
||||
providerUserSession: { accessToken: token },
|
||||
query,
|
||||
}) {
|
||||
return this.#withErrorHandling('provider.zoom.download.error', async () => {
|
||||
// meeting id + file id required
|
||||
// cc files don't have an ID or size
|
||||
|
|
@ -167,7 +173,11 @@ class Zoom extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
async size({ id: meetingId, token, query }) {
|
||||
async size({
|
||||
id: meetingId,
|
||||
providerUserSession: { accessToken: token },
|
||||
query,
|
||||
}) {
|
||||
return this.#withErrorHandling('provider.zoom.size.error', async () => {
|
||||
const client = await getClient({ token })
|
||||
const { recordingStart, recordingId: fileId } = query
|
||||
|
|
@ -183,7 +193,7 @@ class Zoom extends Provider {
|
|||
})
|
||||
}
|
||||
|
||||
async logout({ companion, token }) {
|
||||
async logout({ companion, providerUserSession: { accessToken: token } }) {
|
||||
return this.#withErrorHandling('provider.zoom.logout.error', async () => {
|
||||
const { key, secret } = await companion.getProviderCredentials()
|
||||
|
||||
|
|
|
|||
|
|
@ -13,16 +13,13 @@ describe('handle deauthorization callback', () => {
|
|||
nock('https://api.zoom.us').post('/oauth/data/compliance').reply(200)
|
||||
|
||||
test('providers without support for callback endpoint', () => {
|
||||
return (
|
||||
request(authServer)
|
||||
.post('/dropbox/deauthorization/callback')
|
||||
.set('Content-Type', 'application/json')
|
||||
.send({
|
||||
foo: 'bar',
|
||||
})
|
||||
// @todo consider receiving 501 instead
|
||||
.expect(500)
|
||||
)
|
||||
return request(authServer)
|
||||
.post('/dropbox/deauthorization/callback')
|
||||
.set('Content-Type', 'application/json')
|
||||
.send({
|
||||
foo: 'bar',
|
||||
})
|
||||
.expect(500)
|
||||
})
|
||||
|
||||
test('validate that request credentials match', () => {
|
||||
|
|
|
|||
|
|
@ -117,14 +117,11 @@ class CameraScreen extends Component<CameraScreenProps> {
|
|||
/>
|
||||
</div>
|
||||
) : (
|
||||
// eslint-disable-next-line jsx-a11y/media-has-caption
|
||||
<video
|
||||
/* eslint-disable-next-line no-return-assign */
|
||||
ref={(videoElement) => (this.videoElement = videoElement!)}
|
||||
className={`uppy-Webcam-video ${
|
||||
mirror ? 'uppy-Webcam-video--mirrored' : ''
|
||||
}`}
|
||||
/* eslint-disable-next-line react/jsx-props-no-spreading */
|
||||
{...videoProps}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ const paths = Object.fromEntries(
|
|||
const require = createRequire(packageRoot)
|
||||
for (const pkg of uppyDeps) {
|
||||
const nickname = pkg.slice('@uppy/'.length)
|
||||
// eslint-disable-next-line import/no-dynamic-require
|
||||
const pkgJson = require(`../${nickname}/package.json`)
|
||||
if (pkgJson.main) {
|
||||
yield [
|
||||
|
|
@ -89,7 +88,7 @@ for await (const dirent of dir) {
|
|||
if (!dirent.isDirectory()) {
|
||||
const { name } = dirent
|
||||
const ext = extname(name)
|
||||
if (ext !== '.js' && ext !== '.jsx') continue // eslint-disable-line no-continue
|
||||
if (ext !== '.js' && ext !== '.jsx') continue
|
||||
const filePath =
|
||||
basename(dirent.path) === name
|
||||
? dirent.path // Some versions of Node.js give the full path as dirent.path.
|
||||
|
|
@ -100,14 +99,14 @@ for await (const dirent of dir) {
|
|||
.replace(
|
||||
// The following regex aims to capture all imports and reexports of local .js(x) files to replace it to .ts(x)
|
||||
// It's far from perfect and will have false positives and false negatives.
|
||||
/((?:^|\n)(?:import(?:\s+\w+\s+from)?|export\s*\*\s*from|(?:import|export)\s*(?:\{[^}]*\}|\*\s*as\s+\w+\s)\s*from)\s*["']\.\.?\/[^'"]+\.)js(x?["'])/g, // eslint-disable-line max-len
|
||||
/((?:^|\n)(?:import(?:\s+\w+\s+from)?|export\s*\*\s*from|(?:import|export)\s*(?:\{[^}]*\}|\*\s*as\s+\w+\s)\s*from)\s*["']\.\.?\/[^'"]+\.)js(x?["'])/g,
|
||||
'$1ts$2',
|
||||
)
|
||||
.replace(
|
||||
// The following regex aims to capture all local package.json imports.
|
||||
/\nimport \w+ from ['"]..\/([^'"]+\/)*package.json['"]\n/g,
|
||||
(originalImport) =>
|
||||
`\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n` +
|
||||
`\n` +
|
||||
`// @ts-ignore We don't want TS to generate types for the package.json${originalImport}`,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue