Socket
Socket
Sign inDemoInstall

@uppy/companion-client

Package Overview
Dependencies
Maintainers
6
Versions
88
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@uppy/companion-client - npm Package Compare versions

Comparing version 3.4.0 to 3.4.1

7

CHANGELOG.md
# @uppy/companion-client
## 3.4.1
Released: 2023-09-29
Included in: Uppy v3.17.0
- @uppy/companion-client: fix a refresh token race condition (Mikael Finstad / #4695)
## 3.4.0

@@ -4,0 +11,0 @@

44

lib/Provider.js

@@ -164,23 +164,33 @@ 'use strict';

// throw Object.assign(new Error(), { isAuthError: true }) // testing simulate access token expired (to refresh token)
// A better way to test this is for example with Google Drive:
// While uploading, go to your google account settings,
// "Third-party apps & services", then click "Companion" and "Remove access".
return await super.request(...arguments);
} catch (err) {
if (!err.isAuthError) throw err; // only handle auth errors (401 from provider)
// only handle auth errors (401 from provider), and only handle them if we have a (refresh) token
if (!err.isAuthError || !(await _classPrivateFieldLooseBase(this, _getAuthToken)[_getAuthToken]())) throw err;
if (_classPrivateFieldLooseBase(this, _refreshingTokenPromise)[_refreshingTokenPromise] == null) {
// Many provider requests may be starting at once, however refresh token should only be called once.
// Once a refresh token operation has started, we need all other request to wait for this operation (atomically)
_classPrivateFieldLooseBase(this, _refreshingTokenPromise)[_refreshingTokenPromise] = (async () => {
try {
const response = await super.request({
path: this.refreshTokenUrl(),
method: 'POST'
});
await this.setAuthToken(response.uppyAuthToken);
} catch (refreshTokenErr) {
if (refreshTokenErr.isAuthError) {
// if refresh-token has failed with auth error, delete token, so we don't keep trying to refresh in future
await _classPrivateFieldLooseBase(this, _removeAuthToken)[_removeAuthToken]();
}
throw err;
} finally {
_classPrivateFieldLooseBase(this, _refreshingTokenPromise)[_refreshingTokenPromise] = undefined;
}
})();
}
await _classPrivateFieldLooseBase(this, _refreshingTokenPromise)[_refreshingTokenPromise];
// Many provider requests may be starting at once, however refresh token should only be called once.
// Once a refresh token operation has started, we need all other request to wait for this operation (atomically)
_classPrivateFieldLooseBase(this, _refreshingTokenPromise)[_refreshingTokenPromise] = (async () => {
try {
const response = await super.request({
path: this.refreshTokenUrl(),
method: 'POST'
});
await this.setAuthToken(response.uppyAuthToken);
} finally {
_classPrivateFieldLooseBase(this, _refreshingTokenPromise)[_refreshingTokenPromise] = undefined;
}
})();
await _classPrivateFieldLooseBase(this, _refreshingTokenPromise)[_refreshingTokenPromise];
// now retry the request with our new refresh token

@@ -187,0 +197,0 @@ return super.request(...arguments);

@@ -15,3 +15,3 @@ 'use strict';

const packageJson = {
"version": "3.4.0"
"version": "3.4.1"
}; // Remove the trailing slash so we can always safely append /xyz.

@@ -18,0 +18,0 @@ function stripSlash(url) {

{
"name": "@uppy/companion-client",
"description": "Client library for communication with Companion. Intended for use in Uppy plugins.",
"version": "3.4.0",
"version": "3.4.1",
"license": "MIT",

@@ -25,8 +25,8 @@ "main": "lib/index.js",

"dependencies": {
"@uppy/utils": "^5.5.0",
"@uppy/utils": "^5.5.1",
"namespace-emitter": "^2.0.1"
},
"devDependencies": {
"@jest/globals": "^29.0.0"
"vitest": "^0.34.5"
}
}

@@ -164,19 +164,30 @@ 'use strict'

// throw Object.assign(new Error(), { isAuthError: true }) // testing simulate access token expired (to refresh token)
// A better way to test this is for example with Google Drive:
// While uploading, go to your google account settings,
// "Third-party apps & services", then click "Companion" and "Remove access".
return await super.request(...args)
} catch (err) {
if (!err.isAuthError) throw err // only handle auth errors (401 from provider)
// only handle auth errors (401 from provider), and only handle them if we have a (refresh) token
if (!err.isAuthError || !(await this.#getAuthToken())) throw err
await this.#refreshingTokenPromise
if (this.#refreshingTokenPromise == null) {
// Many provider requests may be starting at once, however refresh token should only be called once.
// Once a refresh token operation has started, we need all other request to wait for this operation (atomically)
this.#refreshingTokenPromise = (async () => {
try {
const response = await super.request({ path: this.refreshTokenUrl(), method: 'POST' })
await this.setAuthToken(response.uppyAuthToken)
} catch (refreshTokenErr) {
if (refreshTokenErr.isAuthError) {
// if refresh-token has failed with auth error, delete token, so we don't keep trying to refresh in future
await this.#removeAuthToken()
}
throw err
} finally {
this.#refreshingTokenPromise = undefined
}
})()
}
// Many provider requests may be starting at once, however refresh token should only be called once.
// Once a refresh token operation has started, we need all other request to wait for this operation (atomically)
this.#refreshingTokenPromise = (async () => {
try {
const response = await super.request({ path: this.refreshTokenUrl(), method: 'POST' })
await this.setAuthToken(response.uppyAuthToken)
} finally {
this.#refreshingTokenPromise = undefined
}
})()
await this.#refreshingTokenPromise

@@ -183,0 +194,0 @@

@@ -1,2 +0,2 @@

import { describe, it, expect } from '@jest/globals'
import { describe, it, expect } from 'vitest'
import RequestClient from './RequestClient.js'

@@ -3,0 +3,0 @@

@@ -1,2 +0,2 @@

import { afterEach, beforeEach, jest, describe, it, expect } from '@jest/globals'
import { afterEach, beforeEach, vi, describe, it, expect } from 'vitest'
import UppySocket from './Socket.js'

@@ -10,5 +10,5 @@

beforeEach(() => {
webSocketConstructorSpy = jest.fn()
webSocketCloseSpy = jest.fn()
webSocketSendSpy = jest.fn()
webSocketConstructorSpy = vi.fn()
webSocketCloseSpy = vi.fn()
webSocketSendSpy = vi.fn()

@@ -126,3 +126,3 @@ globalThis.WebSocket = class WebSocket {

const emitterListenerMock = jest.fn()
const emitterListenerMock = vi.fn()
uppySocket.on('hi', emitterListenerMock)

@@ -142,3 +142,3 @@

const emitterListenerMock = jest.fn()
const emitterListenerMock = vi.fn()
uppySocket.on('hi', emitterListenerMock)

@@ -167,3 +167,3 @@

const emitterListenerMock = jest.fn()
const emitterListenerMock = vi.fn()
uppySocket.once('hi', emitterListenerMock)

@@ -170,0 +170,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc