Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/call check for revocation #1372

Merged
merged 6 commits into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions docs/api/cozy-client/classes/CozyClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Cozy-Client will automatically call `this.login()` if provided with a token and

*Defined in*

[packages/cozy-client/src/CozyClient.js:1612](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1612)
[packages/cozy-client/src/CozyClient.js:1616](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1616)

***

Expand Down Expand Up @@ -199,7 +199,7 @@ Cozy-Client will automatically call `this.login()` if provided with a token and

*Defined in*

[packages/cozy-client/src/CozyClient.js:1587](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1587)
[packages/cozy-client/src/CozyClient.js:1591](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1591)

***

Expand Down Expand Up @@ -471,7 +471,7 @@ If `oauth` options are passed, stackClient is an OAuthStackClient.

*Defined in*

[packages/cozy-client/src/CozyClient.js:1567](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1567)
[packages/cozy-client/src/CozyClient.js:1571](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1571)

***

Expand Down Expand Up @@ -516,7 +516,7 @@ The document that has been deleted

*Defined in*

[packages/cozy-client/src/CozyClient.js:1638](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1638)
[packages/cozy-client/src/CozyClient.js:1642](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1642)

***

Expand Down Expand Up @@ -747,7 +747,7 @@ Creates an association that is linked to the store.

*Defined in*

[packages/cozy-client/src/CozyClient.js:1620](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1620)
[packages/cozy-client/src/CozyClient.js:1624](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1624)

***

Expand Down Expand Up @@ -867,7 +867,7 @@ getInstanceOptions - Returns current instance options, such as domain or app slu

*Defined in*

[packages/cozy-client/src/CozyClient.js:1647](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1647)
[packages/cozy-client/src/CozyClient.js:1651](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1651)

***

Expand Down Expand Up @@ -937,7 +937,7 @@ the store up, which in turn will update the `<Query>`s and re-render the data.

*Defined in*

[packages/cozy-client/src/CozyClient.js:1627](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1627)
[packages/cozy-client/src/CozyClient.js:1631](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1631)

***

Expand All @@ -959,7 +959,7 @@ Sets public attribute and emits event related to revocation

*Defined in*

[packages/cozy-client/src/CozyClient.js:1538](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1538)
[packages/cozy-client/src/CozyClient.js:1542](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1542)

***

Expand All @@ -981,7 +981,7 @@ Emits event when token is refreshed

*Defined in*

[packages/cozy-client/src/CozyClient.js:1549](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1549)
[packages/cozy-client/src/CozyClient.js:1553](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1553)

***

Expand Down Expand Up @@ -1089,7 +1089,7 @@ loadInstanceOptionsFromDOM - Loads the dataset injected by the Stack in web page

*Defined in*

[packages/cozy-client/src/CozyClient.js:1658](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1658)
[packages/cozy-client/src/CozyClient.js:1662](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1662)

***

Expand All @@ -1107,7 +1107,7 @@ For now only retrieving capabilities is supported

*Defined in*

[packages/cozy-client/src/CozyClient.js:1679](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1679)
[packages/cozy-client/src/CozyClient.js:1683](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1683)

***

Expand Down Expand Up @@ -1365,7 +1365,7 @@ All documents matching the query

*Defined in*

[packages/cozy-client/src/CozyClient.js:1634](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1634)
[packages/cozy-client/src/CozyClient.js:1638](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1638)

***

Expand Down Expand Up @@ -1604,7 +1604,7 @@ Saves multiple documents in one batch

*Defined in*

[packages/cozy-client/src/CozyClient.js:1725](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1725)
[packages/cozy-client/src/CozyClient.js:1729](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1729)

***

Expand All @@ -1628,7 +1628,7 @@ set some data in the store.

*Defined in*

[packages/cozy-client/src/CozyClient.js:1698](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1698)
[packages/cozy-client/src/CozyClient.js:1702](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1702)

***

Expand All @@ -1652,7 +1652,7 @@ At any time put an error function

*Defined in*

[packages/cozy-client/src/CozyClient.js:1711](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1711)
[packages/cozy-client/src/CozyClient.js:1715](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1715)

***

Expand Down Expand Up @@ -1728,7 +1728,7 @@ Contains the fetched token and the client information. These should be stored an

*Defined in*

[packages/cozy-client/src/CozyClient.js:1718](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1718)
[packages/cozy-client/src/CozyClient.js:1722](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/CozyClient.js#L1722)

***

Expand Down
32 changes: 18 additions & 14 deletions docs/api/cozy-stack-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,6 @@ Main API against the `cozy-stack` server.
* [CozyStackClient](#CozyStackClient)
* [.collection(doctype)](#CozyStackClient+collection) ⇒ [<code>DocumentCollection</code>](#DocumentCollection)
* [.fetch(method, path, [body], [opts])](#CozyStackClient+fetch) ⇒ <code>object</code>
* [.checkForRevocation()](#CozyStackClient+checkForRevocation)
* [.refreshToken()](#CozyStackClient+refreshToken) ⇒ <code>Promise</code>
* [.fetchJSON(method, path, body, options)](#CozyStackClient+fetchJSON) ⇒ <code>object</code>
* [.setToken(token)](#CozyStackClient+setToken)
Expand Down Expand Up @@ -340,12 +339,6 @@ Fetches an endpoint in an authorized way.
| [body] | <code>object</code> | | The payload. |
| [opts] | <code>object</code> | <code>{}</code> | Options for fetch |

<a name="CozyStackClient+checkForRevocation"></a>

### cozyStackClient.checkForRevocation()
Returns whether the client has been revoked on the server

**Kind**: instance method of [<code>CozyStackClient</code>](#CozyStackClient)
<a name="CozyStackClient+refreshToken"></a>

### cozyStackClient.refreshToken() ⇒ <code>Promise</code>
Expand Down Expand Up @@ -1264,6 +1257,7 @@ through OAuth.
* [.setOAuthOptions(options)](#OAuthClient+setOAuthOptions)
* [.resetClient()](#OAuthClient+resetClient)
* [.setPassphraseFlagship(params)](#OAuthClient+setPassphraseFlagship) ⇒ <code>object</code>
* [.checkForRevocation()](#OAuthClient+checkForRevocation) ⇒ <code>Promise.&lt;boolean&gt;</code>

<a name="OAuthClient+doRegistration"></a>

Expand Down Expand Up @@ -1493,6 +1487,14 @@ More info: https://docs.cozy.io/en/cozy-stack/settings/#post-settingspassphrasef
| params.privateKey | <code>string</code> | private key (crypted) used for sharing ciphers from the vault |
| params.iterations | <code>string</code> | number of KDF iterations applied when hashing the master password |

<a name="OAuthClient+checkForRevocation"></a>

### oAuthClient.checkForRevocation() ⇒ <code>Promise.&lt;boolean&gt;</code>
Check if the OAuth client's has been revoked.
If this is the case, call the onRevocationChange callback

**Kind**: instance method of [<code>OAuthClient</code>](#OAuthClient)
**Returns**: <code>Promise.&lt;boolean&gt;</code> - A Promise that resolves to `false` if client is still valid, or `true` if it has been revoked.
<a name="OAuthClientsCollection"></a>

## OAuthClientsCollection
Expand Down Expand Up @@ -2419,6 +2421,7 @@ Document representing a io.cozy.oauth.clients
* [.setOAuthOptions(options)](#OAuthClient+setOAuthOptions)
* [.resetClient()](#OAuthClient+resetClient)
* [.setPassphraseFlagship(params)](#OAuthClient+setPassphraseFlagship) ⇒ <code>object</code>
* [.checkForRevocation()](#OAuthClient+checkForRevocation) ⇒ <code>Promise.&lt;boolean&gt;</code>

<a name="OAuthClient+doRegistration"></a>

Expand Down Expand Up @@ -2648,6 +2651,14 @@ More info: https://docs.cozy.io/en/cozy-stack/settings/#post-settingspassphrasef
| params.privateKey | <code>string</code> | private key (crypted) used for sharing ciphers from the vault |
| params.iterations | <code>string</code> | number of KDF iterations applied when hashing the master password |

<a name="OAuthClient+checkForRevocation"></a>

### oAuthClient.checkForRevocation() ⇒ <code>Promise.&lt;boolean&gt;</code>
Check if the OAuth client's has been revoked.
If this is the case, call the onRevocationChange callback

**Kind**: instance method of [<code>OAuthClient</code>](#OAuthClient)
**Returns**: <code>Promise.&lt;boolean&gt;</code> - A Promise that resolves to `false` if client is still valid, or `true` if it has been revoked.
<a name="FetchChangesReturnValue"></a>

## FetchChangesReturnValue ⇒ [<code>FetchChangesReturnValue</code>](#FetchChangesReturnValue)
Expand Down Expand Up @@ -2879,7 +2890,6 @@ Define a recipient that can be used as target of a sharing
* [CozyStackClient](#CozyStackClient) : <code>object</code>
* [.collection(doctype)](#CozyStackClient+collection) ⇒ [<code>DocumentCollection</code>](#DocumentCollection)
* [.fetch(method, path, [body], [opts])](#CozyStackClient+fetch) ⇒ <code>object</code>
* [.checkForRevocation()](#CozyStackClient+checkForRevocation)
* [.refreshToken()](#CozyStackClient+refreshToken) ⇒ <code>Promise</code>
* [.fetchJSON(method, path, body, options)](#CozyStackClient+fetchJSON) ⇒ <code>object</code>
* [.setToken(token)](#CozyStackClient+setToken)
Expand Down Expand Up @@ -2914,12 +2924,6 @@ Fetches an endpoint in an authorized way.
| [body] | <code>object</code> | | The payload. |
| [opts] | <code>object</code> | <code>{}</code> | Options for fetch |

<a name="CozyStackClient+checkForRevocation"></a>

### cozyStackClient.checkForRevocation()
Returns whether the client has been revoked on the server

**Kind**: instance method of [<code>CozyStackClient</code>](#CozyStackClient)
<a name="CozyStackClient+refreshToken"></a>

### cozyStackClient.refreshToken() ⇒ <code>Promise</code>
Expand Down
6 changes: 5 additions & 1 deletion packages/cozy-client/src/CozyClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -1531,7 +1531,11 @@ instantiation of the client.`
* Returns whether the client has been revoked on the server
*/
async checkForRevocation() {
return this.stackClient.checkForRevocation()
if (this.stackClient instanceof OAuthClient) {
return this.stackClient.checkForRevocation()
} else {
throw 'checkForRevocation is only implemented for OAutClient'
}
Crash-- marked this conversation as resolved.
Show resolved Hide resolved
}

/** Sets public attribute and emits event related to revocation */
Expand Down
31 changes: 31 additions & 0 deletions packages/cozy-client/src/CozyClient.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2060,3 +2060,34 @@ describe('document creation', () => {
expect(updatedDoc.data.relationships.authors.data[0]._id).toBe(1)
})
})

describe('CozyClient revocation handling', () => {
let client
let mockCallback

beforeEach(() => {
client = new CozyClient({})
client.stackClient.refreshToken = jest.fn().mockImplementation(() => {
client.stackClient.onRevocationChange(true)
})

mockCallback = jest.fn()
client.on('revoked', mockCallback)
})

it('should call "revoked" event when token is expired', async () => {
await client.stackClient.refreshToken()

expect(mockCallback).toHaveBeenCalledTimes(1)
})

it('should not call "revoked" event when token is not expired', async () => {
client.stackClient.refreshToken = jest.fn().mockImplementation(() => {
client.stackClient.onRevocationChange(false)
})

await client.stackClient.refreshToken()

expect(mockCallback).not.toHaveBeenCalled()
})
})
34 changes: 14 additions & 20 deletions packages/cozy-stack-client/src/CozyStackClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ import ShortcutsCollection, { SHORTCUTS_DOCTYPE } from './ShortcutsCollection'
import ContactsCollection, { CONTACTS_DOCTYPE } from './ContactsCollection'
import getIconURL from './getIconURL'
import logDeprecate from './logDeprecate'
import errors from './errors'
import { fetchWithXMLHttpRequest, shouldXMLHTTPRequestBeUsed } from './xhrFetch'
import MicroEE from 'microee'
import { FetchError } from './errors'
import errors, { FetchError } from './errors'
import logger from './logger'
import PromiseCache from './promise-cache'

Expand All @@ -34,10 +33,6 @@ const normalizeUri = uriArg => {
return uri
}

const isRevocationError = err => {
return err.message && errors.CLIENT_NOT_FOUND.test(err.message)
}

/**
* Main API against the `cozy-stack` server.
*/
Expand All @@ -53,7 +48,17 @@ class CozyStackClient {
this.jobs = new JobCollection(this)
this._promiseCache = new PromiseCache()
}
isRevocationError(err) {
const message = err?.message

if (!message) return false

if (
errors.CLIENT_NOT_FOUND.test(err.message) ||
errors.UNREGISTERED_CLIENT.test(err.message)
)
return true
}
/**
* Creates a {@link DocumentCollection} instance.
*
Expand Down Expand Up @@ -141,7 +146,7 @@ class CozyStackClient {
}
return response
} catch (err) {
if (isRevocationError(err)) {
if (this.isRevocationError(err)) {
this.onRevocationChange(true)
}
throw err
Expand All @@ -160,18 +165,6 @@ class CozyStackClient {
}
}

/**
* Returns whether the client has been revoked on the server
*/
async checkForRevocation() {
try {
await this.fetchInformation()
return false
} catch (err) {
return isRevocationError(err)
}
}

/**
* Retrieves a new app token by refreshing the currently used token.
*
Expand Down Expand Up @@ -244,7 +237,8 @@ class CozyStackClient {
} catch (e) {
if (
errors.EXPIRED_TOKEN.test(e.message) ||
errors.INVALID_TOKEN.test(e.message)
errors.INVALID_TOKEN.test(e.message) ||
errors.INVALID_TOKEN_ALT.test(e.message)
) {
try {
await this._promiseCache.exec(
Expand Down
Loading
Loading