diff --git a/meilisearch-dart b/meilisearch-dart
new file mode 160000
index 00000000..1d22b746
--- /dev/null
+++ b/meilisearch-dart
@@ -0,0 +1 @@
+Subproject commit 1d22b746b5207fbdd149076f4e0f4756f803fe8d
diff --git a/src/Meilisearch/Errors/MeilisearchTenantTokenApiKeyInvalid.cs b/src/Meilisearch/Errors/MeilisearchTenantTokenApiKeyInvalid.cs
index 2e77ec32..b9a50d3a 100644
--- a/src/Meilisearch/Errors/MeilisearchTenantTokenApiKeyInvalid.cs
+++ b/src/Meilisearch/Errors/MeilisearchTenantTokenApiKeyInvalid.cs
@@ -12,7 +12,7 @@ public class MeilisearchTenantTokenApiKeyInvalid : Exception
/// Initializes a new instance of the class.
///
public MeilisearchTenantTokenApiKeyInvalid()
- : base("Cannot generate a signed token without a valid apiKey. Provide one in the MeilisearchClient instance or in the method params.")
+ : base("Cannot generate a signed token without a valid apiKey. Provide one in the MeilisearchClient instance or in the method params. The key MUST be at least 16 characters, or 128 bits")
{
}
}
diff --git a/src/Meilisearch/TenantToken.cs b/src/Meilisearch/TenantToken.cs
index 1fe20025..5651a1cd 100644
--- a/src/Meilisearch/TenantToken.cs
+++ b/src/Meilisearch/TenantToken.cs
@@ -16,12 +16,12 @@ public class TenantToken
/// JWT string
public static string GenerateToken(string apiKeyUid, TenantTokenRules searchRules, string apiKey, DateTime? expiresAt)
{
- if (String.IsNullOrEmpty(apiKeyUid))
+ if (string.IsNullOrEmpty(apiKeyUid))
{
throw new MeilisearchTenantTokenApiKeyUidInvalid();
}
- if (String.IsNullOrEmpty(apiKey) || apiKey.Length < 8)
+ if (string.IsNullOrEmpty(apiKey) || apiKey.Length < 16)
{
throw new MeilisearchTenantTokenApiKeyInvalid();
}
diff --git a/src/Meilisearch/TenantTokenRules.cs b/src/Meilisearch/TenantTokenRules.cs
index 31e0aa83..fcff7d80 100644
--- a/src/Meilisearch/TenantTokenRules.cs
+++ b/src/Meilisearch/TenantTokenRules.cs
@@ -10,11 +10,31 @@ public class TenantTokenRules
{
private readonly object _rules;
- public TenantTokenRules(Dictionary rules)
+ ///
+ /// Initializes a new instance of the class based on a rules json object.
+ ///
+ ///
+ ///
+ /// example:
+ ///
+ /// {'*': {"filter": 'tag = Tale'}}
+ ///
+ ///
+ public TenantTokenRules(IReadOnlyDictionary rules)
{
_rules = rules;
}
+ ///
+ /// Initializes a new instance of the class based on a rules string array.
+ ///
+ ///
+ ///
+ /// example:
+ ///
+ /// ['books']
+ ///
+ ///
public TenantTokenRules(string[] rules)
{
_rules = rules;
diff --git a/tests/Meilisearch.Tests/TenantTokenTests.cs b/tests/Meilisearch.Tests/TenantTokenTests.cs
index ef875667..8a56791e 100644
--- a/tests/Meilisearch.Tests/TenantTokenTests.cs
+++ b/tests/Meilisearch.Tests/TenantTokenTests.cs
@@ -7,7 +7,8 @@
namespace Meilisearch.Tests
{
- public abstract class TenantTokenTests : IAsyncLifetime where TFixture : IndexFixture
+ public abstract class TenantTokenTests : IAsyncLifetime
+ where TFixture : IndexFixture
{
private readonly TenantTokenRules _searchRules = new TenantTokenRules(new string[] { "*" });
@@ -70,9 +71,21 @@ public void ClientThrowsIfNoKeyIsAvailable()
);
}
+
+ [Fact]
+ public void ClientThrowsIfKeyIsLessThan128Bits()
+ {
+ var customClient = new MeilisearchClient(_fixture.MeilisearchAddress(), "masterKey");
+ Assert.Throws(
+ () => customClient.GenerateTenantToken(_uid, _searchRules)
+ );
+ }
+
+
+
[Theory]
[MemberData(nameof(PossibleSearchRules))]
- public async void SearchesSuccessfullyWithTheNewToken(dynamic data)
+ public async void SearchesSuccessfullyWithTheNewToken(object data)
{
var keyOptions = new Key
{
@@ -83,10 +96,26 @@ public async void SearchesSuccessfullyWithTheNewToken(dynamic data)
};
var createdKey = await _client.CreateKeyAsync(keyOptions);
var admClient = new MeilisearchClient(_fixture.MeilisearchAddress(), createdKey.KeyUid);
- var task = await admClient.Index(_indexName).UpdateFilterableAttributesAsync(new string[] { "tag", "book_id" });
+ var task = await admClient
+ .Index(_indexName)
+ .UpdateFilterableAttributesAsync(new string[] { "tag", "book_id" });
await admClient.Index(_indexName).WaitForTaskAsync(task.TaskUid);
- var token = admClient.GenerateTenantToken(createdKey.Uid, new TenantTokenRules(data));
+ TenantTokenRules tokenRules;
+ if (data is string[] dataStringArray)
+ {
+ tokenRules = new TenantTokenRules(dataStringArray);
+ }
+ else if (data is IReadOnlyDictionary dataDictionary)
+ {
+ tokenRules = new TenantTokenRules(dataDictionary);
+ }
+ else
+ {
+ throw new Exception("Invalid data type");
+ }
+
+ var token = admClient.GenerateTenantToken(createdKey.Uid, tokenRules);
var customClient = new MeilisearchClient(_fixture.MeilisearchAddress(), token);
await customClient.Index(_indexName).SearchAsync(string.Empty);
@@ -105,12 +134,17 @@ public async Task SearchFailsWhenTokenIsExpired()
var createdKey = await _client.CreateKeyAsync(keyOptions);
var admClient = new MeilisearchClient(_fixture.MeilisearchAddress(), createdKey.KeyUid);
- var token = admClient.GenerateTenantToken(createdKey.Uid, new TenantTokenRules(new[] { "*" }), expiresAt: DateTime.UtcNow.AddSeconds(1));
+ var token = admClient.GenerateTenantToken(
+ createdKey.Uid,
+ new TenantTokenRules(new[] { "*" }),
+ expiresAt: DateTime.UtcNow.AddSeconds(1)
+ );
var customClient = new MeilisearchClient(_fixture.MeilisearchAddress(), token);
Thread.Sleep(TimeSpan.FromSeconds(2));
- await Assert.ThrowsAsync(async () =>
- await customClient.Index(_indexName).SearchAsync(string.Empty));
+ await Assert.ThrowsAsync(
+ async () => await customClient.Index(_indexName).SearchAsync(string.Empty)
+ );
}
[Fact]
@@ -126,29 +160,61 @@ public async void SearchSucceedsWhenTokenIsNotExpired()
var createdKey = await _client.CreateKeyAsync(keyOptions);
var admClient = new MeilisearchClient(_fixture.MeilisearchAddress(), createdKey.KeyUid);
- var token = admClient.GenerateTenantToken(createdKey.Uid, new TenantTokenRules(new[] { "*" }), expiresAt: DateTime.UtcNow.AddMinutes(1));
+ var token = admClient.GenerateTenantToken(
+ createdKey.Uid,
+ new TenantTokenRules(new[] { "*" }),
+ expiresAt: DateTime.UtcNow.AddMinutes(1)
+ );
var customClient = new MeilisearchClient(_fixture.MeilisearchAddress(), token);
await customClient.Index(_indexName).SearchAsync(string.Empty);
}
- public static IEnumerable