Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
1652: Update crypto statement to fix vite issue r=curquiza a=brunoocasali

After the introduction of this PR meilisearch#1616 we had a bunch of issues related to vite configuration on client projects as shown here meilisearch/meilisearch-js-plugins#1299

This PR introduces the rollback needed to fix the consumer's code. If this change is not enough, I will completely reverse the PR 1616.


Edit:

I was able to solve the issue, by using this branch with this [reproduction repo](https://github.com/flexchar/meili-issue-1299) I could build the project and also run the application without any issue.

But this change introduces some breaking changes in the JWT code:

Now it is required to use await: `await client.generateTenantToken(..)` instead of just `client.generateTenantToken(..)`.

Co-authored-by: Bruno Casali <[email protected]>
  • Loading branch information
meili-bors[bot] and brunoocasali authored May 15, 2024
2 parents 2f37b74 + e0b1e71 commit 9639f78
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 48 deletions.
2 changes: 1 addition & 1 deletion .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@ tenant_token_guide_generate_sdk_1: |-
const apiKeyUid = '85c3c2f9-bdd6-41f1-abd8-11fcf80e0f76'
const expiresAt = new Date('2025-12-20') // optional
const token = client.generateTenantToken(apiKeyUid, searchRules, {
const token = await client.generateTenantToken(apiKeyUid, searchRules, {
apiKey: apiKey,
expiresAt: expiresAt,
})
Expand Down
4 changes: 1 addition & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
version: "3.8"

services:
package:
image: node:16
image: node:18
tty: true
stdin_open: true
working_dir: /home/package
Expand Down
8 changes: 4 additions & 4 deletions src/clients/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -475,11 +475,11 @@ class Client {
_apiKeyUid: string,
_searchRules: TokenSearchRules,
_options?: TokenOptions
): string {
): Promise<string> {
const error = new Error()
throw new Error(
`Meilisearch: failed to generate a tenant token. Generation of a token only works in a node environment \n ${error.stack}.`
)
error.message = `Meilisearch: failed to generate a tenant token. Generation of a token only works in a node environment \n ${error.stack}.`

return Promise.reject(error)
}
}

Expand Down
12 changes: 8 additions & 4 deletions src/clients/node-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@ class MeiliSearch extends Client {
* @param options - Token options to customize some aspect of the token.
* @returns The token in JWT format.
*/
generateTenantToken(
async generateTenantToken(
apiKeyUid: string,
searchRules: TokenSearchRules,
options?: TokenOptions
): string {
): Promise<string> {
if (typeof window === 'undefined') {
return this.tokens.generateTenantToken(apiKeyUid, searchRules, options)
return await this.tokens.generateTenantToken(
apiKeyUid,
searchRules,
options
)
}
return super.generateTenantToken(apiKeyUid, searchRules, options)
return await super.generateTenantToken(apiKeyUid, searchRules, options)
}
}
export { MeiliSearch }
15 changes: 10 additions & 5 deletions src/token.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Config, TokenSearchRules, TokenOptions } from './types'
import { createHmac } from 'crypto'
import { MeiliSearchError } from './errors'
import { validateUuid4 } from './utils'

Expand All @@ -15,7 +14,13 @@ function encode64(data: any) {
* @param encodedPayload - Payload of the token in base64.
* @returns The signature of the token in base64.
*/
function sign(apiKey: string, encodedHeader: string, encodedPayload: string) {
async function sign(
apiKey: string,
encodedHeader: string,
encodedPayload: string
) {
const { createHmac } = await import('crypto')

return createHmac('sha256', apiKey)
.update(`${encodedHeader}.${encodedPayload}`)
.digest('base64')
Expand Down Expand Up @@ -132,11 +137,11 @@ class Token {
* @param options - Token options to customize some aspect of the token.
* @returns The token in JWT format.
*/
generateTenantToken(
async generateTenantToken(
apiKeyUid: string,
searchRules: TokenSearchRules,
options?: TokenOptions
): string {
): Promise<string> {
const apiKey = options?.apiKey || this.config.apiKey || ''
const uid = apiKeyUid || ''
const expiresAt = options?.expiresAt
Expand All @@ -145,7 +150,7 @@ class Token {

const encodedHeader = createHeader()
const encodedPayload = createPayload({ searchRules, uid, expiresAt })
const signature = sign(apiKey, encodedHeader, encodedPayload)
const signature = await sign(apiKey, encodedHeader, encodedPayload)

return `${encodedHeader}.${encodedPayload}.${signature}`
}
Expand Down
55 changes: 24 additions & 31 deletions tests/token.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
} from './utils/meilisearch-test-utils'
import { createHmac } from 'crypto'
import MeiliSearch from '../src'
import { MeiliSearchError } from '../src/errors'

const HASH_ALGORITHM = 'HS256'
const TOKEN_TYP = 'JWT'
Expand Down Expand Up @@ -44,7 +43,7 @@ describe.each([{ permission: 'Admin' }])(
const client = await getClient(permission)
const apiKey = await getKey(permission)
const { uid } = await client.getKey(apiKey)
const token = client.generateTenantToken(uid, [], {})
const token = await client.generateTenantToken(uid, [], {})
const [header64] = token.split('.')

// header
Expand All @@ -57,7 +56,7 @@ describe.each([{ permission: 'Admin' }])(
const client = await getClient(permission)
const apiKey = await getKey(permission)
const { uid } = await client.getKey(apiKey)
const token = client.generateTenantToken(uid, [], {})
const token = await client.generateTenantToken(uid, [], {})
const [header64, payload64, signature64] = token.split('.')

// signature
Expand All @@ -75,7 +74,7 @@ describe.each([{ permission: 'Admin' }])(
const client = await getClient(permission)
const apiKey = await getKey(permission)
const { uid } = await client.getKey(apiKey)
const token = client.generateTenantToken(uid, [], {})
const token = await client.generateTenantToken(uid, [], {})
const [_, payload64] = token.split('.')

// payload
Expand All @@ -90,7 +89,7 @@ describe.each([{ permission: 'Admin' }])(
const client = await getClient(permission)
const apiKey = await getKey(permission)
const { uid } = await client.getKey(apiKey)
const token = client.generateTenantToken(uid, [UID])
const token = await client.generateTenantToken(uid, [UID])
const [_, payload64] = token.split('.')

// payload
Expand All @@ -105,7 +104,7 @@ describe.each([{ permission: 'Admin' }])(
const client = await getClient(permission)
const apiKey = await getKey(permission)
const { uid } = await client.getKey(apiKey)
const token = client.generateTenantToken(uid, { [UID]: {} })
const token = await client.generateTenantToken(uid, { [UID]: {} })
const [_, payload64] = token.split('.')

// payload
Expand All @@ -120,7 +119,7 @@ describe.each([{ permission: 'Admin' }])(
const apiKey = await getKey(permission)
const { uid } = await client.getKey(apiKey)

const token = client.generateTenantToken(uid, ['*'])
const token = await client.generateTenantToken(uid, ['*'])

const searchClient = new MeiliSearch({ host: HOST, apiKey: token })

Expand All @@ -137,7 +136,7 @@ describe.each([{ permission: 'Admin' }])(
indexes: [UID],
})
const client = await getClient(permission)
const token = client.generateTenantToken(uid, ['*'], {
const token = await client.generateTenantToken(uid, ['*'], {
apiKey: key,
})

Expand All @@ -152,7 +151,7 @@ describe.each([{ permission: 'Admin' }])(
const date = new Date('December 17, 4000 03:24:00')
const apiKey = await getKey(permission)
const { uid } = await client.getKey(apiKey)
const token = client.generateTenantToken(uid, ['*'], {
const token = await client.generateTenantToken(uid, ['*'], {
expiresAt: date,
})

Expand All @@ -171,18 +170,18 @@ describe.each([{ permission: 'Admin' }])(
const { uid } = await client.getKey(apiKey)
const date = new Date('December 17, 2000 03:24:00')

expect(() =>
client.generateTenantToken(uid, ['*'], {
expiresAt: date,
})
).toThrow()
expect(
client.generateTenantToken(uid, ['*'], { expiresAt: date })
).rejects.toThrow(
`Meilisearch: The expiresAt field must be a date in the future.`
)
})

test(`${permission} key: Search in tenant token with specific index set to null`, async () => {
const client = await getClient(permission)
const apiKey = await getKey(permission)
const { uid } = await client.getKey(apiKey)
const token = client.generateTenantToken(uid, {
const token = await client.generateTenantToken(uid, {
[UID]: null,
})

Expand All @@ -202,7 +201,7 @@ describe.each([{ permission: 'Admin' }])(
const client = await getClient(permission)
const apiKey = await getKey(permission)
const { uid } = await client.getKey(apiKey)
const token = client.generateTenantToken(uid, {
const token = await client.generateTenantToken(uid, {
[UID]: { filter: 'id = 2' },
})

Expand All @@ -216,7 +215,7 @@ describe.each([{ permission: 'Admin' }])(
const client = await getClient(permission)
const apiKey = await getKey(permission)
const { uid } = await client.getKey(apiKey)
const token = client.generateTenantToken(uid, [])
const token = await client.generateTenantToken(uid, [])

const searchClient = new MeiliSearch({ host: HOST, apiKey: token })

Expand All @@ -230,7 +229,7 @@ describe.each([{ permission: 'Admin' }])(
const client = await getClient(permission)
const apiKey = await getKey(permission)
const { uid } = await client.getKey(apiKey)
const token = client.generateTenantToken(uid, { misc: null })
const token = await client.generateTenantToken(uid, { misc: null })

const searchClient = new MeiliSearch({ host: HOST, apiKey: token })

Expand All @@ -246,38 +245,32 @@ describe.each([{ permission: 'Admin' }])(
const { uid } = await client.getKey(apiKey)
const date = new Date('December 17, 2000 03:24:00')

expect(() =>
expect(
client.generateTenantToken(
uid,
{},
{
expiresAt: date,
}
)
).toThrowError(
new MeiliSearchError(
`Meilisearch: The expiresAt field must be a date in the future.`
)
).rejects.toThrow(
`Meilisearch: The expiresAt field must be a date in the future.`
)
})

test(`${permission} key: Creates tenant token with wrong uid type throws an error`, async () => {
const client = await getClient(permission)

expect(() => client.generateTenantToken('1234', ['*'])).toThrowError(
new MeiliSearchError(
`Meilisearch: The uid of your key is not a valid uuid4. To find out the uid of your key use getKey().`
)
expect(client.generateTenantToken('1234', ['*'])).rejects.toThrow(
`Meilisearch: The uid of your key is not a valid uuid4. To find out the uid of your key use getKey().`
)
})

test(`${permission} key: Creates a tenant token with no api key in client and in parameters throws an error`, () => {
const client = new MeiliSearch({ host: HOST })

expect(() => client.generateTenantToken('123', [])).toThrowError(
new MeiliSearchError(
`Meilisearch: The API key used for the token generation must exist and be of type string.`
)
expect(client.generateTenantToken('123', [])).rejects.toThrow(
`Meilisearch: The API key used for the token generation must exist and be of type string.`
)
})
}
Expand Down

0 comments on commit 9639f78

Please sign in to comment.