From 5f339f2a0232a1030d8f8c8909857f954c342eb8 Mon Sep 17 00:00:00 2001 From: HAHWUL Date: Wed, 26 Jun 2024 23:57:47 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=A7=AA=20Implement=20endpoint=20compa?= =?UTF-8?q?rison=20logic=20in=20diff=20analysis=20for=20#330?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/unit_test/models/endpoint_spec.cr | 32 +++++++++++++++++++ spec/unit_test/models/output_builder_spec.cr | 33 ++++++++++++++++++++ src/models/endpoint.cr | 20 ++++++++++++ src/output_builder/diff.cr | 20 ++++++++++-- 4 files changed, 102 insertions(+), 3 deletions(-) diff --git a/spec/unit_test/models/endpoint_spec.cr b/spec/unit_test/models/endpoint_spec.cr index 2dae8de6..60dec4b8 100644 --- a/spec/unit_test/models/endpoint_spec.cr +++ b/spec/unit_test/models/endpoint_spec.cr @@ -62,3 +62,35 @@ describe "Initialize 4 arguments" do endpoint.details.code_paths[0].line.should eq(line) end end + +describe "Endpoint equality" do + it "same endpoints" do + endpoint1 = Endpoint.new("/abcd", "GET") + endpoint2 = Endpoint.new("/abcd", "GET") + (endpoint1 == endpoint2).should eq(true) + end + + it "different endpoints" do + endpoint1 = Endpoint.new("/abcd", "GET") + endpoint2 = Endpoint.new("/abcd", "POST") + (endpoint1 == endpoint2).should eq(false) + end + + it "same endpoints with params" do + endpoint1 = Endpoint.new("/abcd", "GET", [Param.new("a", "b", "query")]) + endpoint2 = Endpoint.new("/abcd", "GET", [Param.new("a", "b", "query")]) + (endpoint1 == endpoint2).should eq(true) + end + + it "different endpoints with params" do + endpoint1 = Endpoint.new("/abcd", "GET", [Param.new("a", "b", "query")]) + endpoint2 = Endpoint.new("/abcd", "GET", [Param.new("a", "b", "json")]) + (endpoint1 == endpoint2).should eq(false) + end + + it "same endpoints and suffled params" do + endpoint1 = Endpoint.new("/abcd", "GET", [Param.new("a", "b", "query"), Param.new("c", "d", "json")]) + endpoint2 = Endpoint.new("/abcd", "GET", [Param.new("c", "d", "json"), Param.new("a", "b", "query")]) + (endpoint1 == endpoint2).should eq(true) + end +end diff --git a/spec/unit_test/models/output_builder_spec.cr b/spec/unit_test/models/output_builder_spec.cr index 1abdf996..49c022db 100644 --- a/spec/unit_test/models/output_builder_spec.cr +++ b/spec/unit_test/models/output_builder_spec.cr @@ -85,4 +85,37 @@ describe OutputBuilderDiff do result[:added].should eq [Endpoint.new("GET", "/new")] result[:removed].should eq [Endpoint.new("GET", "/old")] end + + it "calculates the diff correctly with multiple endpoints" do + old_endpoints = [Endpoint.new("GET", "/old"), Endpoint.new("GET", "/old2")] + new_endpoints = [Endpoint.new("GET", "/new"), Endpoint.new("GET", "/new2")] + builder = OutputBuilderDiff.new options + + result = builder.diff(new_endpoints, old_endpoints) + + result[:added].should eq [Endpoint.new("GET", "/new"), Endpoint.new("GET", "/new2")] + result[:removed].should eq [Endpoint.new("GET", "/old"), Endpoint.new("GET", "/old2")] + end + + it "calculates the diff correctly with multiple endpoints and different methods" do + old_endpoints = [Endpoint.new("GET", "/old"), Endpoint.new("POST", "/old2")] + new_endpoints = [Endpoint.new("GET", "/new"), Endpoint.new("POST", "/new2")] + builder = OutputBuilderDiff.new options + + result = builder.diff(new_endpoints, old_endpoints) + + result[:added].should eq [Endpoint.new("GET", "/new"), Endpoint.new("POST", "/new2")] + result[:removed].should eq [Endpoint.new("GET", "/old"), Endpoint.new("POST", "/old2")] + end + + it "calculates the diff correctly with multiple endpoints and different methods and params" do + old_endpoints = [Endpoint.new("GET", "/old", [Param.new("a", "b", "query"), Param.new("c", "d", "json")])] + new_endpoints = [Endpoint.new("GET", "/new", [Param.new("e", "f", "query"), Param.new("g", "h", "json")])] + builder = OutputBuilderDiff.new options + + result = builder.diff(new_endpoints, old_endpoints) + + result[:added].should eq [Endpoint.new("GET", "/new", [Param.new("e", "f", "query"), Param.new("g", "h", "json")])] + result[:removed].should eq [Endpoint.new("GET", "/old", [Param.new("a", "b", "query"), Param.new("c", "d", "json")])] + end end diff --git a/src/models/endpoint.cr b/src/models/endpoint.cr index ebaccdd5..8da408cd 100644 --- a/src/models/endpoint.cr +++ b/src/models/endpoint.cr @@ -50,6 +50,8 @@ struct Endpoint params_hash["query"] = {} of String => String params_hash["json"] = {} of String => String params_hash["form"] = {} of String => String + params_hash["header"] = {} of String => String + params_hash["cookie"] = {} of String => String @params.each do |param| params_hash[param.param_type][param.name] = param.value @@ -57,6 +59,24 @@ struct Endpoint params_hash end + + def ==(other : Endpoint) : Bool + return false unless @url == other.url + return false unless @method == other.method + + self_params = params_to_hash + other_params = other.params_to_hash + + # Ensure both hashes have the same set of keys before comparing values + common_keys = self_params.keys & other_params.keys + return false unless common_keys.size == self_params.keys.size && common_keys.size == other_params.keys.size + + common_keys.each do |key| + return false unless self_params[key] == other_params[key] + end + + true + end end struct Param diff --git a/src/output_builder/diff.cr b/src/output_builder/diff.cr index ef254081..1711d45f 100644 --- a/src/output_builder/diff.cr +++ b/src/output_builder/diff.cr @@ -6,9 +6,23 @@ require "yaml" class OutputBuilderDiff < OutputBuilder def diff(new_endpoints : Array(Endpoint), old_endpoints : Array(Endpoint)) - added = new_endpoints - old_endpoints - removed = old_endpoints - new_endpoints - changed = new_endpoints & old_endpoints + added = [] of Endpoint + changed = [] of Endpoint + removed = [] of Endpoint + + new_endpoints.each do |new_endpoint| + matching_old_endpoint = old_endpoints.find { |old_endpoint| old_endpoint.url == new_endpoint.url && old_endpoint.method == new_endpoint.method } + if matching_old_endpoint + changed << new_endpoint unless new_endpoint == matching_old_endpoint + else + added << new_endpoint + end + end + + old_endpoints.each do |old_endpoint| + matching_new_endpoint = new_endpoints.find { |new_endpoint| new_endpoint.url == old_endpoint.url && new_endpoint.method == old_endpoint.method } + removed << old_endpoint unless matching_new_endpoint + end {added: added, removed: removed, changed: changed} end From ad83accf9daf4f385a4e1d2fcaba419a247072f1 Mon Sep 17 00:00:00 2001 From: HAHWUL Date: Thu, 27 Jun 2024 08:36:07 +0900 Subject: [PATCH 2/2] chore: Update version to 0.16.1 --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- shard.yml | 2 +- snap/snapcraft.yaml | 2 +- src/noir.cr | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7b2ccc35..ca414142 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -23,7 +23,7 @@ If applicable, add screenshots to help explain your problem. **Versions** - OS: [e.g. macos, linux] - - Version [e.g. v0.16.0] + - Version [e.g. v0.16.1] **Additional context** Add any other context about the problem here. diff --git a/shard.yml b/shard.yml index c42f7de3..83ba6731 100644 --- a/shard.yml +++ b/shard.yml @@ -1,6 +1,6 @@ # Project Metadata name: noir -version: 0.16.0 +version: 0.16.1 authors: - hahwul - ksg97031 diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 35ce416b..843f55af 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: noir base: core20 -version: 0.16.0 +version: 0.16.1 summary: Attack surface detector that identifies endpoints by static analysis. description: | Noir is an open-source project specializing in identifying attack surfaces for enhanced whitebox security testing and security pipeline. diff --git a/src/noir.cr b/src/noir.cr index ae1ae4ac..de802dd2 100644 --- a/src/noir.cr +++ b/src/noir.cr @@ -6,7 +6,7 @@ require "./options.cr" require "./techs/techs.cr" module Noir - VERSION = "0.16.0" + VERSION = "0.16.1" end # Print banner