Skip to content

Commit 533d9cb

Browse files
committed
Change IP Address from string to IPAddress type.
1 parent d1c0326 commit 533d9cb

6 files changed

Lines changed: 56 additions & 11 deletions

File tree

Source/Singulink.Net.Http.Api.Service/HttpContextExtensions.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,34 @@
1+
using System.Collections.Concurrent;
2+
using System.Reflection;
3+
14
namespace Singulink.Net.Http.Api.Service;
25

36
/// <summary>
47
/// Extension methods for <see cref="HttpContext"/>.
58
/// </summary>
69
public static class HttpContextExtensions
710
{
11+
private static readonly ConcurrentDictionary<ParameterInfo, (bool IsRequired, SessionAccessOptions Options)> _bindSessionTokenParamCache = [];
12+
13+
/// <summary>
14+
/// Binds a session token from the HTTP context based on the parameter's nullability and attributes.
15+
/// </summary>
16+
public static async ValueTask<TSessionToken?> BindSessionTokenAsync<TSessionToken>(this HttpContext httpContext, ParameterInfo parameter)
17+
where TSessionToken : class, ISessionToken
18+
{
19+
var (isRequired, options) = _bindSessionTokenParamCache.GetOrAdd(parameter, p =>
20+
{
21+
var nullabilityInfo = new NullabilityInfoContext().Create(parameter);
22+
23+
var sessionAccessAttr = p.GetCustomAttribute<SessionAccessAttribute>();
24+
return (nullabilityInfo.WriteState is NullabilityState.NotNull, sessionAccessAttr?.Options ?? default);
25+
});
26+
27+
return isRequired ?
28+
await httpContext.GetRequiredSessionTokenAsync<TSessionToken>(options) :
29+
await httpContext.GetSessionTokenAsync<TSessionToken>(options);
30+
}
31+
832
/// <summary>
933
/// Gets the session context from the HTTP context.
1034
/// </summary>

Source/Singulink.Net.Http.Api.Service/HttpSessionContext.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public override async ValueTask<TSessionToken> GetRequiredTokenAsync(SessionAcce
181181
/// <inheritdoc/>
182182
public override async Task<TSessionToken> SignInAsync(bool persistent, Func<SignInInfo, Task<TSessionToken>> createSessionFunc)
183183
{
184-
var signInInfo = new SignInInfo(Device, IpAddressString, persistent ? _options.PersistentSessionExpiry : _options.TempSessionExpiry, persistent);
184+
var signInInfo = new SignInInfo(Device, IpAddress, persistent ? _options.PersistentSessionExpiry : _options.TempSessionExpiry, persistent);
185185
var token = await createSessionFunc(signInInfo);
186186

187187
// TODO: Clear token? Cache on HTTP context (here and in GetTokenAsync)?
@@ -271,7 +271,7 @@ private void ValidateUserIdPreconditionHeader(TSessionToken sessionToken, bool o
271271
if (sessionData.Generation != sessionToken.Generation + 1 ||
272272
timeSinceDataRefresh > _options.MultipleRefreshGracePeriod ||
273273
sessionData.Device != Device ||
274-
sessionData.IpAddress != IpAddressString)
274+
!Equals(sessionData.IpAddress, IpAddress))
275275
{
276276
// Remove session as it may have been compromised.
277277

@@ -284,7 +284,7 @@ private void ValidateUserIdPreconditionHeader(TSessionToken sessionToken, bool o
284284
var utcNow = DateTime.UtcNow;
285285

286286
sessionData.Device = Device;
287-
sessionData.IpAddress = IpAddressString;
287+
sessionData.IpAddress = IpAddress;
288288
sessionData.RefreshedUtc = utcNow;
289289
sessionData.ValidFor = sessionData.IsPersistent ? _options.PersistentSessionExpiry : _options.TempSessionExpiry;
290290

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace Singulink.Net.Http.Api.Service;
2+
3+
/// <summary>
4+
/// Attribute for configuring options when binding session tokens from HTTP contexts.
5+
/// </summary>
6+
[AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)]
7+
public class SessionAccessAttribute : Attribute
8+
{
9+
/// <summary>
10+
/// Gets options for configuring session access behavior.
11+
/// </summary>
12+
public SessionAccessOptions Options { get; }
13+
14+
/// <summary>
15+
/// Initializes a new instance of the <see cref="SessionAccessAttribute"/> class.
16+
/// </summary>
17+
/// <param name="options">Options for configuring session access behavior.</param>
18+
public SessionAccessAttribute(SessionAccessOptions options)
19+
{
20+
Options = options;
21+
}
22+
}

Source/Singulink.Net.Http.Api.Service/SessionContext.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@ public abstract class SessionContext<TSessionToken> : IBindableFromHttpContext<S
2020
/// </summary>
2121
public abstract IPAddress? IpAddress { get; }
2222

23-
/// <summary>
24-
/// Gets the IP address of the current request as a string. If the IP address cannot be determined, returns "Unknown".
25-
/// </summary>
26-
public string IpAddressString => field ??= IpAddress?.ToString() ?? "Unknown";
27-
2823
/// <summary>
2924
/// Gets the session token from the current request. If the user is not signed in, throws an <see cref="UnauthorizedApiException"/>.
3025
/// </summary>

Source/Singulink.Net.Http.Api.Service/SignInInfo.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
using System.Net;
2+
13
namespace Singulink.Net.Http.Api.Service;
24

35
/// <summary>
46
/// Contains information about a sign-in request, such as device info, IP address, session expiry, and persistence.
57
/// </summary>
68
public class SignInInfo
79
{
8-
internal SignInInfo(string device, string ipAddress, TimeSpan sessionExpiry, bool persistent)
10+
internal SignInInfo(string device, IPAddress? ipAddress, TimeSpan sessionExpiry, bool persistent)
911
{
1012
Device = device;
1113
IpAddress = ipAddress;
@@ -21,7 +23,7 @@ internal SignInInfo(string device, string ipAddress, TimeSpan sessionExpiry, boo
2123
/// <summary>
2224
/// Gets the IP address of the device making the sign-in request.
2325
/// </summary>
24-
public string IpAddress { get; }
26+
public IPAddress? IpAddress { get; }
2527

2628
/// <summary>
2729
/// Gets the duration after which the session will expire.

Source/Singulink.Net.Http.Api/ISessionData.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Net;
2+
13
namespace Singulink.Net.Http.Api;
24

35
/// <summary>
@@ -13,7 +15,7 @@ public interface ISessionData : ISessionTokenRefreshInfo
1315
/// <summary>
1416
/// Gets or sets the last IP address associated with the session.
1517
/// </summary>
16-
string IpAddress { get; set; }
18+
IPAddress? IpAddress { get; set; }
1719

1820
/// <summary>
1921
/// Gets or sets the date and time when the session was last refreshed (in UTC).

0 commit comments

Comments
 (0)