Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9277256

Browse files
Improved ID obfuscation (#1775)
* Make running kiota tests faster by turning off default handlers (such as retries) * Remove redundant TranslateAsync calls in tests * Fix inconsistencies in test assertions * Assert on obfuscated links, mention sqids * Switch from int to long, use invariant culture, use singleton codec * Add API to remove a resource from the graph (after assembly scanning) * Add test support for obfuscation in operations * Add annotation to hide underlying resource ID type in OpenAPI document * Add OpenAPI tests for ID obfuscation
1 parent 23be010 commit 9277256

File tree

133 files changed

+14500
-297
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+14500
-297
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.Annotations;
2+
3+
/// <summary>
4+
/// Hides the underlying resource ID type in OpenAPI documents.
5+
/// </summary>
6+
/// <remarks>
7+
/// For example, when used on a resource type that implements <c><![CDATA[IIdentifiable<long>]]></c>, excludes the <c>format</c> property on the ID
8+
/// schema. As a result, the ID type is displayed as <c>string</c> instead of
9+
/// <c>
10+
/// string($int64)
11+
/// </c>
12+
/// in SwaggerUI.
13+
/// </remarks>
14+
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct)]
15+
public sealed class HideResourceIdTypeInOpenApiAttribute : Attribute;

‎src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
using System.Reflection;
12
using JsonApiDotNetCore.Configuration;
3+
using JsonApiDotNetCore.Middleware;
4+
using JsonApiDotNetCore.OpenApi.Swashbuckle.Annotations;
25
using Microsoft.OpenApi.Models;
36
using Swashbuckle.AspNetCore.SwaggerGen;
47

@@ -7,32 +10,48 @@ namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
710
internal sealed class ResourceIdSchemaGenerator
811
{
912
private readonly SchemaGenerator _defaultSchemaGenerator;
13+
private readonly IControllerResourceMapping _controllerResourceMapping;
1014

11-
public ResourceIdSchemaGenerator(SchemaGenerator defaultSchemaGenerator)
15+
public ResourceIdSchemaGenerator(SchemaGenerator defaultSchemaGenerator,IControllerResourceMappingcontrollerResourceMapping)
1216
{
1317
ArgumentNullException.ThrowIfNull(defaultSchemaGenerator);
18+
ArgumentNullException.ThrowIfNull(controllerResourceMapping);
1419

1520
_defaultSchemaGenerator = defaultSchemaGenerator;
21+
_controllerResourceMapping = controllerResourceMapping;
1622
}
1723

18-
public OpenApiSchema GenerateSchema(ResourceTyperesourceType, SchemaRepository schemaRepository)
24+
public OpenApiSchema GenerateSchema(ParameterInfoparameter, SchemaRepository schemaRepository)
1925
{
20-
ArgumentNullException.ThrowIfNull(resourceType);
26+
ArgumentNullException.ThrowIfNull(parameter);
27+
ArgumentNullException.ThrowIfNull(schemaRepository);
28+
29+
Type? controllerType = parameter.Member.ReflectedType;
30+
ConsistencyGuard.ThrowIf(controllerType == null);
31+
32+
ResourceType? resourceType = _controllerResourceMapping.GetResourceTypeForController(controllerType);
33+
ConsistencyGuard.ThrowIf(resourceType == null);
2134

22-
return GenerateSchema(resourceType.IdentityClrType, schemaRepository);
35+
return GenerateSchema(resourceType, schemaRepository);
2336
}
2437

25-
public OpenApiSchema GenerateSchema(TyperesourceIdClrType, SchemaRepository schemaRepository)
38+
public OpenApiSchema GenerateSchema(ResourceTyperesourceType, SchemaRepository schemaRepository)
2639
{
27-
ArgumentNullException.ThrowIfNull(resourceIdClrType);
40+
ArgumentNullException.ThrowIfNull(resourceType);
2841
ArgumentNullException.ThrowIfNull(schemaRepository);
2942

30-
OpenApiSchema idSchema = _defaultSchemaGenerator.GenerateSchema(resourceIdClrType, schemaRepository);
43+
OpenApiSchema idSchema = _defaultSchemaGenerator.GenerateSchema(resourceType.IdentityClrType, schemaRepository);
3144
ConsistencyGuard.ThrowIf(idSchema.Reference != null);
3245

3346
idSchema.Type = "string";
3447

35-
if (resourceIdClrType != typeof(string))
48+
var hideIdTypeAttribute = resourceType.ClrType.GetCustomAttribute<HideResourceIdTypeInOpenApiAttribute>();
49+
50+
if (hideIdTypeAttribute != null)
51+
{
52+
idSchema.Format = null;
53+
}
54+
else if (resourceType.IdentityClrType != typeof(string))
3655
{
3756
// When using string IDs, it's discouraged (but possible) to use an empty string as primary key value, because
3857
// some things won't work: get-by-id, update and delete resource are impossible, and rendered links are unusable.

‎src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/JsonApiSchemaGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public OpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepo
3434

3535
if (parameterInfo is { Name: "id" } && IsJsonApiParameter(parameterInfo))
3636
{
37-
return _resourceIdSchemaGenerator.GenerateSchema(schemaType, schemaRepository);
37+
return _resourceIdSchemaGenerator.GenerateSchema(parameterInfo, schemaRepository);
3838
}
3939

4040
DocumentSchemaGenerator? schemaGenerator = GetDocumentSchemaGenerator(schemaType);

‎src/JsonApiDotNetCore/Configuration/ResourceGraphBuilder.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,32 @@ private static bool IsImplicitManyToManyJoinEntity(IEntityType entityType)
167167
return entityType is { IsPropertyBag: true, HasSharedClrType: true };
168168
}
169169

170+
/// <summary>
171+
/// Removes a JSON:API resource.
172+
/// </summary>
173+
/// <typeparam name="TResource">
174+
/// The resource CLR type.
175+
/// </typeparam>
176+
public ResourceGraphBuilder Remove<TResource>()
177+
where TResource : class, IIdentifiable
178+
{
179+
return Remove(typeof(TResource));
180+
}
181+
182+
/// <summary>
183+
/// Removes a JSON:API resource.
184+
/// </summary>
185+
/// <param name="resourceClrType">
186+
/// The resource CLR type.
187+
/// </param>
188+
public ResourceGraphBuilder Remove(Type resourceClrType)
189+
{
190+
ArgumentNullException.ThrowIfNull(resourceClrType);
191+
192+
_resourceTypesByClrType.Remove(resourceClrType);
193+
return this;
194+
}
195+
170196
/// <summary>
171197
/// Adds a JSON:API resource.
172198
/// </summary>

‎test/JsonApiDotNetCoreTests/IntegrationTests/IdObfuscation/BankAccountsController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
namespace JsonApiDotNetCoreTests.IntegrationTests.IdObfuscation;
66

77
public sealed class BankAccountsController(
8-
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<BankAccount, int> resourceService)
8+
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<BankAccount, long> resourceService)
99
: ObfuscatedIdentifiableController<BankAccount>(options, resourceGraph, loggerFactory, resourceService);

‎test/JsonApiDotNetCoreTests/IntegrationTests/IdObfuscation/DebitCardsController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
namespace JsonApiDotNetCoreTests.IntegrationTests.IdObfuscation;
66

77
public sealed class DebitCardsController(
8-
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<DebitCard, int> resourceService)
8+
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<DebitCard, long> resourceService)
99
: ObfuscatedIdentifiableController<DebitCard>(options, resourceGraph, loggerFactory, resourceService);

‎test/JsonApiDotNetCoreTests/IntegrationTests/IdObfuscation/HexadecimalCodec.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,15 @@ namespace JsonApiDotNetCoreTests.IntegrationTests.IdObfuscation;
88

99
internal sealed class HexadecimalCodec
1010
{
11-
public int Decode(string? value)
11+
// This implementation is deliberately simple for demonstration purposes.
12+
// Consider using something more robust, such as https://github.com/sqids/sqids-dotnet.
13+
public static HexadecimalCodec Instance { get; } = new();
14+
15+
private HexadecimalCodec()
16+
{
17+
}
18+
19+
public long Decode(string? value)
1220
{
1321
if (value == null)
1422
{
@@ -25,7 +33,7 @@ public int Decode(string? value)
2533
}
2634

2735
string stringValue = FromHexString(value[1..]);
28-
return int.Parse(stringValue);
36+
return long.Parse(stringValue,CultureInfo.InvariantCulture);
2937
}
3038

3139
private static string FromHexString(string hexString)
@@ -35,22 +43,22 @@ private static string FromHexString(string hexString)
3543
for (int index = 0; index < hexString.Length; index += 2)
3644
{
3745
string hexChar = hexString.Substring(index, 2);
38-
byte bt = byte.Parse(hexChar, NumberStyles.HexNumber);
46+
byte bt = byte.Parse(hexChar, NumberStyles.HexNumber,CultureInfo.InvariantCulture);
3947
bytes.Add(bt);
4048
}
4149

4250
char[] chars = Encoding.ASCII.GetChars([.. bytes]);
4351
return new string(chars);
4452
}
4553

46-
public string? Encode(int value)
54+
public string? Encode(long value)
4755
{
4856
if (value == 0)
4957
{
5058
return null;
5159
}
5260

53-
string stringValue = value.ToString();
61+
string stringValue = value.ToString(CultureInfo.InvariantCulture);
5462
return $"x{ToHexString(stringValue)}";
5563
}
5664

@@ -60,7 +68,7 @@ private static string ToHexString(string value)
6068

6169
foreach (byte bt in Encoding.ASCII.GetBytes(value))
6270
{
63-
builder.Append(bt.ToString("X2"));
71+
builder.Append(bt.ToString("X2",CultureInfo.InvariantCulture));
6472
}
6573

6674
return builder.ToString();

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /