mirror of
https://github.com/ysoftdevs/wapifuzz.git
synced 2026-04-30 12:34:16 +02:00
Init WFuzz state
This commit is contained in:
31
parser/Parser/AttributeParser.cs
Normal file
31
parser/Parser/AttributeParser.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Models;
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
public static class AttributeParser
|
||||
{
|
||||
public static UriAttribute ParseAttribute(OpenApiParameter parameter)
|
||||
{
|
||||
if (parameter.In == ParameterLocation.Path || parameter.In == ParameterLocation.Query)
|
||||
{
|
||||
if (parameter.Schema == null || parameter.Schema.Type == null && parameter.Schema.Format == null)
|
||||
{
|
||||
throw new ArgumentException("We do not know anything useful about passed URI parameter.");
|
||||
}
|
||||
|
||||
UriAttribute attribute = new UriAttribute(parameter.Name, parameter.Required)
|
||||
{
|
||||
ExampleValue = ContentParser.GetStringExampleFromContent(parameter.Example, parameter.Examples) ??
|
||||
ContentParser.GetSingleExample(parameter.Schema?.Example) ??
|
||||
PrimitiveDataTypeExampleGenerator.GenerateExampleValueByType(parameter.Schema.Type, parameter.Schema.Format),
|
||||
Type = parameter.Schema.Type,
|
||||
Format = parameter.Schema.Format
|
||||
};
|
||||
return attribute;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
42
parser/Parser/ContentParser.cs
Normal file
42
parser/Parser/ContentParser.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
public static class ContentParser
|
||||
{
|
||||
public static string GetStringExampleFromContent(IOpenApiAny example, IDictionary<string, OpenApiExample> examples)
|
||||
{
|
||||
return GetSingleExample(example) ?? GetExampleFromExamplesDict(examples);
|
||||
}
|
||||
|
||||
public static string GetSingleExample(IOpenApiAny example)
|
||||
{
|
||||
return example != null ? GetStringFromAnyType(example) : null;
|
||||
}
|
||||
|
||||
// If there are more examples, take the first one
|
||||
// To the future consider creating request for each example
|
||||
static string GetExampleFromExamplesDict(IDictionary<string, OpenApiExample> examples)
|
||||
{
|
||||
return examples.Count > 0 ? GetSingleExample(examples.First().Value.Value) : null;
|
||||
}
|
||||
|
||||
static string GetStringFromAnyType(IOpenApiAny value)
|
||||
{
|
||||
switch (value.AnyType)
|
||||
{
|
||||
case AnyType.Primitive:
|
||||
return OpenApiAnyConvertor.GetPrimitiveValue(value);
|
||||
case AnyType.Object:
|
||||
case AnyType.Array:
|
||||
return OpenApiAnyConvertor.GetJsonValue(value);
|
||||
default:
|
||||
throw new NotImplementedException("This data example type is not supported yet!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
parser/Parser/EndpointParser.cs
Normal file
30
parser/Parser/EndpointParser.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Models;
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
public static class EndpointParser
|
||||
{
|
||||
public static List<Endpoint> ParseAllEndpoints(OpenApiDocument openApiDocument)
|
||||
{
|
||||
List<Endpoint> endpoints = new List<Endpoint>();
|
||||
|
||||
foreach (var path in openApiDocument.Paths)
|
||||
{
|
||||
endpoints.Add(ParseEndpoint(path));
|
||||
}
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
static Endpoint ParseEndpoint(KeyValuePair<string, OpenApiPathItem> path)
|
||||
{
|
||||
Endpoint endpoint = new Endpoint(path.Key);
|
||||
foreach (KeyValuePair<OperationType, OpenApiOperation> operation in path.Value.Operations)
|
||||
{
|
||||
endpoint.Requests.Add(RequestParser.ParseRequest(operation));
|
||||
}
|
||||
return endpoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
parser/Parser/ExamplesParser.cs
Normal file
37
parser/Parser/ExamplesParser.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
public static class ExamplesParser
|
||||
{
|
||||
static readonly List<string> SupportedContentTypes = new List<string> { "application/json", "text/plain" };
|
||||
|
||||
public static string ParseExample(IDictionary<string, OpenApiMediaType> contentDict)
|
||||
{
|
||||
foreach (var supportedContentType in SupportedContentTypes)
|
||||
{
|
||||
if (contentDict.ContainsKey(supportedContentType))
|
||||
return GetSpecificContentTypeExample(contentDict, supportedContentType);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static string GetSpecificContentTypeExample(IDictionary<string, OpenApiMediaType> contentDict, string contentType)
|
||||
{
|
||||
var content = contentDict[contentType];
|
||||
return GetRealExample(content) ?? GetExampleFromSchema(content);
|
||||
}
|
||||
|
||||
static string GetRealExample(OpenApiMediaType content)
|
||||
{
|
||||
return ContentParser.GetStringExampleFromContent(content.Example, content.Examples);
|
||||
}
|
||||
|
||||
static string GetExampleFromSchema(OpenApiMediaType content)
|
||||
{
|
||||
return content.Schema != null ? ContentParser.GetStringExampleFromContent(content.Schema.Example, new Dictionary<string, OpenApiExample>()) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
68
parser/Parser/OpenApiAnyConvertor.cs
Normal file
68
parser/Parser/OpenApiAnyConvertor.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Writers;
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
public static class OpenApiAnyConvertor
|
||||
{
|
||||
public static string GetPrimitiveValue(IOpenApiAny value)
|
||||
{
|
||||
IOpenApiPrimitive primitive = (IOpenApiPrimitive) value;
|
||||
|
||||
switch (primitive.PrimitiveType)
|
||||
{
|
||||
case PrimitiveType.String:
|
||||
OpenApiString stringValue = (OpenApiString) primitive;
|
||||
return stringValue.Value;
|
||||
case PrimitiveType.Boolean:
|
||||
OpenApiBoolean booleanValue = (OpenApiBoolean) primitive;
|
||||
return booleanValue.Value.ToString();
|
||||
case PrimitiveType.Integer:
|
||||
OpenApiInteger integerValue = (OpenApiInteger) primitive;
|
||||
return integerValue.Value.ToString();
|
||||
case PrimitiveType.Long:
|
||||
OpenApiLong longValue = (OpenApiLong) primitive;
|
||||
return longValue.Value.ToString();
|
||||
case PrimitiveType.Float:
|
||||
OpenApiFloat floatValue = (OpenApiFloat) primitive;
|
||||
return floatValue.Value.ToString(CultureInfo.InvariantCulture);
|
||||
case PrimitiveType.Double:
|
||||
OpenApiDouble doubleValue = (OpenApiDouble) primitive;
|
||||
return doubleValue.Value.ToString(CultureInfo.InvariantCulture);
|
||||
case PrimitiveType.Byte:
|
||||
OpenApiByte byteValue = (OpenApiByte) primitive;
|
||||
return Encoding.Default.GetString(byteValue.Value);
|
||||
case PrimitiveType.Binary:
|
||||
OpenApiBinary binaryValue = (OpenApiBinary) primitive;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
foreach (byte byteVal in binaryValue.Value)
|
||||
{
|
||||
builder.Append(Convert.ToString(byteVal, 2).PadLeft(8, '0'));
|
||||
}
|
||||
return builder.ToString();
|
||||
case PrimitiveType.Date:
|
||||
OpenApiDate dateValue = (OpenApiDate) primitive;
|
||||
return dateValue.Value.ToString(CultureInfo.InvariantCulture);
|
||||
case PrimitiveType.DateTime:
|
||||
OpenApiDateTime dateTimeValue = (OpenApiDateTime) primitive;
|
||||
return dateTimeValue.Value.ToString();
|
||||
case PrimitiveType.Password:
|
||||
OpenApiPassword passwordValue = (OpenApiPassword) primitive;
|
||||
return passwordValue.Value;
|
||||
default:
|
||||
throw new NotImplementedException("This data example type is not supported yet!");
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetJsonValue(IOpenApiAny value)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
value.Write(new OpenApiJsonWriter(new StringWriter(builder)), OpenApiDocumentParser.Version);
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
39
parser/Parser/OpenApiDocumentParser.cs
Normal file
39
parser/Parser/OpenApiDocumentParser.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.OpenApi;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.OpenApi.Readers;
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
public static class OpenApiDocumentParser
|
||||
{
|
||||
public static OpenApiSpecVersion Version;
|
||||
public static OpenApiDocument ParseOpenApiDocument(string openApiDocFilePath)
|
||||
{
|
||||
OpenApiDocument openApiDocument;
|
||||
using (FileStream stream = File.Open(openApiDocFilePath, FileMode.Open))
|
||||
{
|
||||
openApiDocument = new OpenApiStreamReader().Read(stream, out var diagnostic);
|
||||
|
||||
StoreDocumentVersion(diagnostic.SpecificationVersion);
|
||||
PrintParsingErrors(diagnostic.Errors);
|
||||
}
|
||||
return openApiDocument;
|
||||
}
|
||||
|
||||
static void PrintParsingErrors(IList<OpenApiError> errors)
|
||||
{
|
||||
foreach (var openApiError in errors)
|
||||
{
|
||||
Console.WriteLine("WARNING: Following parsing error occurs: " + openApiError.Message);
|
||||
}
|
||||
}
|
||||
|
||||
static void StoreDocumentVersion(OpenApiSpecVersion version)
|
||||
{
|
||||
Version = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
parser/Parser/Parser.csproj
Normal file
15
parser/Parser/Parser.csproj
Normal file
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Models\Models.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
48
parser/Parser/PrimitiveDataTypeExampleGenerator.cs
Normal file
48
parser/Parser/PrimitiveDataTypeExampleGenerator.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
// Data types for Open API 2 and OpenAPI 3 are basically the same:
|
||||
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md
|
||||
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md
|
||||
public static class PrimitiveDataTypeExampleGenerator
|
||||
{
|
||||
public static string GenerateExampleValueByType(string type, string format)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case "integer":
|
||||
return "42";
|
||||
case "number":
|
||||
return "42.0";
|
||||
case "boolean":
|
||||
return "True";
|
||||
case "string":
|
||||
{
|
||||
const string example = "example";
|
||||
switch (format)
|
||||
{
|
||||
case null:
|
||||
return example;
|
||||
case "byte":
|
||||
var plainTextBytes = Encoding.UTF8.GetBytes(example);
|
||||
return Encoding.Default.GetString(plainTextBytes);
|
||||
case "binary":
|
||||
return "01234567";
|
||||
case "date":
|
||||
return "2002-10-02";
|
||||
case "date-time":
|
||||
return "2002-10-02T10:00:00-05:00";
|
||||
case "password":
|
||||
return example;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotImplementedException("Unrecognized value data type! Check the OpenAPI documentation for new types!");
|
||||
}
|
||||
}
|
||||
}
|
||||
59
parser/Parser/RequestParser.cs
Normal file
59
parser/Parser/RequestParser.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Models;
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
public static class RequestParser
|
||||
{
|
||||
public static Request ParseRequest(KeyValuePair<OperationType, OpenApiOperation> operation)
|
||||
{
|
||||
var request = new Request(operation.Key.ToString())
|
||||
{
|
||||
Summary = operation.Value.Summary,
|
||||
BodyExample = GetBodyExample(operation.Value.RequestBody),
|
||||
BodySchema = GetBodySchema(operation.Value.RequestBody),
|
||||
UriAttributes = ParseUriAttributes(operation.Value),
|
||||
Responses = ParseResponses(operation.Value)
|
||||
};
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
static string GetBodyExample(OpenApiRequestBody body)
|
||||
{
|
||||
return body != null ? ExamplesParser.ParseExample(body.Content) : null;
|
||||
}
|
||||
|
||||
static Dictionary<string, object> GetBodySchema(OpenApiRequestBody body)
|
||||
{
|
||||
return body != null ? SchemaParser.ParseSchema(body.Content) : null;
|
||||
}
|
||||
|
||||
static List<UriAttribute> ParseUriAttributes(OpenApiOperation operation)
|
||||
{
|
||||
List<UriAttribute> attributes = new List<UriAttribute>();
|
||||
foreach (var parameter in operation.Parameters)
|
||||
{
|
||||
var attribute = AttributeParser.ParseAttribute(parameter);
|
||||
if (attribute != null)
|
||||
{
|
||||
attributes.Add(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
static List<Response> ParseResponses(OpenApiOperation operation)
|
||||
{
|
||||
List<Response> responses = new List<Response>();
|
||||
foreach (var openApiResponse in operation.Responses)
|
||||
{
|
||||
responses.Add(ResponseParser.ParseResponse(openApiResponse));
|
||||
}
|
||||
|
||||
return responses;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
parser/Parser/ResponseParser.cs
Normal file
40
parser/Parser/ResponseParser.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Models;
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
public static class ResponseParser
|
||||
{
|
||||
public static Response ParseResponse(KeyValuePair<string, OpenApiResponse> openApiResponse)
|
||||
{
|
||||
string example = null;
|
||||
if (openApiResponse.Value != null)
|
||||
example = ExamplesParser.ParseExample(openApiResponse.Value.Content);
|
||||
|
||||
var response = new Response
|
||||
{
|
||||
Example = example,
|
||||
StatusCode = ParseStatusCode(openApiResponse.Key)
|
||||
};
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static int ParseStatusCode(string responseKey)
|
||||
{
|
||||
if (responseKey == "default")
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!int.TryParse(responseKey, out var statusCode))
|
||||
{
|
||||
throw new NotImplementedException("Provided status code is not supported: " + responseKey);
|
||||
}
|
||||
|
||||
return statusCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
parser/Parser/SchemaParser.cs
Normal file
78
parser/Parser/SchemaParser.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
public static class SchemaParser
|
||||
{
|
||||
public static Dictionary<string, object> ParseSchema(IDictionary<string, OpenApiMediaType> contentDict)
|
||||
{
|
||||
return contentDict.ContainsKey("application/json") ? ParseSchemaProperties(contentDict["application/json"].Schema) : null;
|
||||
}
|
||||
|
||||
static Dictionary<string, object> ParseSchemaProperties(OpenApiSchema schema)
|
||||
{
|
||||
Dictionary<string, object> parsedSchema = new Dictionary<string, object>();
|
||||
|
||||
if (schema.AdditionalPropertiesAllowed && schema.AdditionalProperties != null)
|
||||
{
|
||||
Dictionary<string, object> nestedSchema = ParseSchemaProperties(schema.AdditionalProperties);
|
||||
|
||||
// Create single object with string key: "AdditionalPropertyExample1" and with nested schema as it is in documentation
|
||||
// There can be multiple nested objects, but we want to reduce number of generated test cases
|
||||
parsedSchema.Add("AdditionalPropertyExample1", nestedSchema);
|
||||
}
|
||||
|
||||
if (schema.AllOf.Count > 0)
|
||||
{
|
||||
foreach (var openApiSchema in schema.AllOf)
|
||||
{
|
||||
Dictionary<string, object> nestedSchema = ParseSchemaProperties(openApiSchema);
|
||||
parsedSchema = MergeTwoDictionaries(nestedSchema, parsedSchema);
|
||||
}
|
||||
}
|
||||
|
||||
if (schema.OneOf.Count > 0)
|
||||
{
|
||||
Dictionary<string, object> nestedSchema = ParseSchemaProperties(schema.OneOf.First());
|
||||
parsedSchema = MergeTwoDictionaries(nestedSchema, parsedSchema);
|
||||
}
|
||||
|
||||
if (schema.AnyOf.Count > 0)
|
||||
{
|
||||
Dictionary<string, object> nestedSchema = ParseSchemaProperties(schema.AnyOf.First());
|
||||
parsedSchema = MergeTwoDictionaries(nestedSchema, parsedSchema);
|
||||
}
|
||||
|
||||
if (schema.Properties != null && schema.Properties.Count > 0)
|
||||
{
|
||||
foreach (var property in schema.Properties)
|
||||
{
|
||||
Dictionary<string, object> nestedSchema = ParseSchemaProperties(property.Value);
|
||||
parsedSchema.Add(property.Key, nestedSchema);
|
||||
}
|
||||
}
|
||||
else if (schema.Type != null && schema.Type.ToLower() == "array")
|
||||
{
|
||||
parsedSchema.Add("Type", schema.Type);
|
||||
Dictionary<string, object> arrayItemsSchema = ParseSchemaProperties(schema.Items);
|
||||
parsedSchema.Add("ArrayItemSchema", arrayItemsSchema);
|
||||
}
|
||||
else if (schema.Type != "object")
|
||||
{
|
||||
parsedSchema.Add("Title", schema.Title);
|
||||
parsedSchema.Add("Type", schema.Type);
|
||||
parsedSchema.Add("Format", schema.Format);
|
||||
parsedSchema.Add("Example", ContentParser.GetSingleExample(schema.Example));
|
||||
}
|
||||
|
||||
return parsedSchema;
|
||||
}
|
||||
|
||||
static Dictionary<string, object> MergeTwoDictionaries(Dictionary<string, object> first, Dictionary<string, object> second)
|
||||
{
|
||||
return new List<Dictionary<string, object>> { first, second }.SelectMany(dict => dict).ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user