-
Notifications
You must be signed in to change notification settings - Fork 3
/
UserAgentSentinelOptions.cs
144 lines (132 loc) · 6.55 KB
/
UserAgentSentinelOptions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using Cuemon.Configuration;
namespace Cuemon.AspNetCore.Http.Headers
{
/// <summary>
/// Configuration options for <see cref="UserAgentSentinelMiddleware"/> and related.
/// </summary>
public class UserAgentSentinelOptions : IValidatableParameterObject
{
/// <summary>
/// Initializes a new instance of the <see cref="UserAgentSentinelOptions"/> class.
/// </summary>
/// <remarks>
/// The following table shows the initial property values for an instance of <see cref="UserAgentSentinelOptions"/>.
/// <list type="table">
/// <listheader>
/// <term>Property</term>
/// <description>Initial Value</description>
/// </listheader>
/// <item>
/// <term><see cref="AllowedUserAgents"/></term>
/// <description><c>new List{string}();</c></description>
/// </item>
/// <item>
/// <term><see cref="BadRequestMessage"/></term>
/// <description>The requirements of the request was not met.</description>
/// </item>
/// <item>
/// <term><see cref="ForbiddenMessage"/></term>
/// <description>The HTTP User-Agent specified was rejected.</description>
/// </item>
/// <item>
/// <term><see cref="RequireUserAgentHeader"/></term>
/// <description><c>false</c></description>
/// </item>
/// <item>
/// <term><see cref="ValidateUserAgentHeader"/></term>
/// <description><c>false</c></description>
/// </item>
/// <item>
/// <term><see cref="ResponseHandler"/></term>
/// <description>A <see cref="HttpResponseMessage"/> initialized to either a HTTP status code 400 or 403 and a body of either <see cref="BadRequestMessage"/> or <see cref="ForbiddenMessage"/>.</description>
/// </item>
/// <item>
/// <term><see cref="UseGenericResponse"/></term>
/// <description><c>false</c></description>
/// </item>
/// </list>
/// </remarks>
public UserAgentSentinelOptions()
{
BadRequestMessage = "The requirements of the request was not met.";
ForbiddenMessage = "The User-Agent specified was rejected.";
AllowedUserAgents = new List<string>();
ResponseHandler = userAgent =>
{
var userAgentIsNullOrWhiteSpace = string.IsNullOrWhiteSpace(userAgent);
var forbidden = !userAgentIsNullOrWhiteSpace &&
ValidateUserAgentHeader &&
AllowedUserAgents.Count > 0 &&
!AllowedUserAgents.Any(allowedUserAgent => userAgent.Equals(allowedUserAgent, StringComparison.OrdinalIgnoreCase));
if (userAgentIsNullOrWhiteSpace || forbidden && UseGenericResponse)
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(BadRequestMessage)
};
}
if (forbidden)
{
return new HttpResponseMessage(HttpStatusCode.Forbidden)
{
Content = new StringContent(ForbiddenMessage)
};
}
return null;
};
}
/// <summary>
/// Gets or sets the function delegate that configures the response in the form of a <see cref="HttpResponseMessage"/>.
/// </summary>
/// <value>The function delegate that configures the response in the form of a <see cref="HttpResponseMessage"/>.</value>
public Func<string, HttpResponseMessage> ResponseHandler { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the produced <see cref="ResponseHandler"/> should be as neutral as possible.
/// </summary>
/// <value><c>true</c> if the produced <see cref="ResponseHandler"/> should be as neutral as possible; otherwise, <c>false</c>.</value>
public bool UseGenericResponse { get; set; }
/// <summary>
/// Gets or sets a value indicating whether a HTTP User-Agent header must be present in the request.
/// </summary>
/// <value><c>true</c> if the HTTP User-Agent header must be present in the request; otherwise, <c>false</c>.</value>
public bool RequireUserAgentHeader { get; set; }
/// <summary>
/// Gets or sets a value indicating whether a HTTP User-Agent header must be validated against <see cref="AllowedUserAgents"/>.
/// </summary>
/// <value><c>true</c> if the HTTP User-Agent header must be validated against <see cref="AllowedUserAgents"/>; otherwise, <c>false</c>.</value>
public bool ValidateUserAgentHeader { get; set; }
/// <summary>
/// Gets or sets a list of whitelisted user agents.
/// </summary>
/// <value>A list of whitelisted user agents.</value>
public IList<string> AllowedUserAgents { get; set; }
/// <summary>
/// Gets or sets the message of a request missing the requirements of a User-Agent header.
/// </summary>
/// <value>The message of a request missing the requirements of a User-Agent header.</value>
public string BadRequestMessage { get; set; }
/// <summary>
/// Gets or sets the message of a request without a valid User-Agent header.
/// </summary>
/// <value>The message of a request without a valid User-Agent header.</value>
public string ForbiddenMessage { get; set; }
/// <summary>
/// Determines whether the public read-write properties of this instance are in a valid state.
/// </summary>
/// <exception cref="InvalidOperationException">
/// <see cref="ResponseHandler"/> cannot be null - or -
/// <see cref="AllowedUserAgents"/> cannot be null.
/// </exception>
/// <remarks>This method is expected to throw exceptions when one or more conditions fails to be in a valid state.</remarks>
public void ValidateOptions()
{
Validator.ThrowIfInvalidState(ResponseHandler == null);
Validator.ThrowIfInvalidState(AllowedUserAgents == null);
}
}
}