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

Update crypto statement to fix vite issue #1652

Merged
merged 1 commit into from
May 15, 2024
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
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 @@
_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}.`

Check warning on line 480 in src/clients/client.ts

View check run for this annotation

Codecov / codecov/patch

src/clients/client.ts#L480

Added line #L480 was not covered by tests

return Promise.reject(error)

Check warning on line 482 in src/clients/client.ts

View check run for this annotation

Codecov / codecov/patch

src/clients/client.ts#L482

Added line #L482 was not covered by tests
}
}

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 @@
* @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)

Check warning on line 33 in src/clients/node-client.ts

View check run for this annotation

Codecov / codecov/patch

src/clients/node-client.ts#L33

Added line #L33 was not covered by tests
}
}
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