diff --git a/spec/functional_test/fixtures/js_restify/app.js b/spec/functional_test/fixtures/js_restify/app.js new file mode 100644 index 0000000..5166fc0 --- /dev/null +++ b/spec/functional_test/fixtures/js_restify/app.js @@ -0,0 +1,32 @@ +const restify = require('restify'); + +function setupServer(server) { + server.get('/', function(req, res, next) { + var userAgent = req.header('X-API-Key'); + var paramName = req.query.name; + + res.send('index'); // Assuming 'index' is a simple response for demonstration + return next(); + }); + + server.post('/upload', function(req, res, next) { + // Restify does not parse cookies by default, so you need to use a plugin or middleware if you want to access cookies + // const auth = req.cookies.auth; // This line needs adjustment if using cookies + const name = req.body.name; + + res.send('index'); // Similarly, adjust according to your actual response handling + return next(); + }); +} + +// Setup Restify server +const server = restify.createServer(); + +server.use(restify.plugins.bodyParser()); // Parse JSON body data +// server.use(restify.plugins.cookieParser()); // Uncomment if you need cookie parsing + +setupServer(server); + +server.listen(3000, function() { + console.log('%s listening at %s', server.name, server.url); +}); diff --git a/spec/functional_test/func_spec.cr b/spec/functional_test/func_spec.cr index a912e8f..6728269 100644 --- a/spec/functional_test/func_spec.cr +++ b/spec/functional_test/func_spec.cr @@ -78,7 +78,7 @@ class FunctionalTester key = endpoint.method.to_s + "::" + endpoint.url.to_s found_endpoint = find_endpoint key if found_endpoint.nil? - it "endpoint [#{key}] not founded" do + it "endpoint [#{key}] not found" do false.should eq true end else diff --git a/spec/functional_test/testers/js_restify_spec.cr b/spec/functional_test/testers/js_restify_spec.cr new file mode 100644 index 0000000..8af6a52 --- /dev/null +++ b/spec/functional_test/testers/js_restify_spec.cr @@ -0,0 +1,17 @@ +require "../func_spec.cr" + +extected_endpoints = [ + Endpoint.new("/", "GET", [ + Param.new("name", "", "query"), + Param.new("X-API-Key", "", "header"), + ]), + Endpoint.new("/upload", "POST", [ + Param.new("name", "", "json"), + Param.new("auth", "", "cookie"), + ]), +] + +FunctionalTester.new("fixtures/js_restify/", { + :techs => 1, + :endpoints => 2, +}, extected_endpoints).test_all diff --git a/spec/unit_test/detector/detect_js_restify_spec.cr b/spec/unit_test/detector/detect_js_restify_spec.cr new file mode 100644 index 0000000..d0f296f --- /dev/null +++ b/spec/unit_test/detector/detect_js_restify_spec.cr @@ -0,0 +1,13 @@ +require "../../../src/detector/detectors/*" + +describe "Detect JS Restify" do + options = default_options() + instance = DetectorJsRestify.new options + + it "require_single_quot" do + instance.detect("index.js", "require('restify')").should eq(true) + end + it "require_double_quot" do + instance.detect("index.js", "require(\"restify\")").should eq(true) + end +end diff --git a/src/analyzer/analyzer.cr b/src/analyzer/analyzer.cr index d6b09e9..1e467de 100644 --- a/src/analyzer/analyzer.cr +++ b/src/analyzer/analyzer.cr @@ -18,6 +18,7 @@ def initialize_analyzers(logger : NoirLogger) analyzers["java_jsp"] = ->analyzer_jsp(Hash(Symbol, String)) analyzers["java_spring"] = ->analyzer_java_spring(Hash(Symbol, String)) analyzers["js_express"] = ->analyzer_express(Hash(Symbol, String)) + analyzers["js_restify"] = ->analyzer_restify(Hash(Symbol, String)) analyzers["kotlin_spring"] = ->analyzer_kotlin_spring(Hash(Symbol, String)) analyzers["oas2"] = ->analyzer_oas2(Hash(Symbol, String)) analyzers["oas3"] = ->analyzer_oas3(Hash(Symbol, String)) diff --git a/src/analyzer/analyzers/analyzer_restify.cr b/src/analyzer/analyzers/analyzer_restify.cr new file mode 100644 index 0000000..9a165a1 --- /dev/null +++ b/src/analyzer/analyzers/analyzer_restify.cr @@ -0,0 +1,111 @@ +require "../../models/analyzer" + +class AnalyzerRestify < Analyzer + def analyze + # Source Analysis + begin + Dir.glob("#{base_path}/**/*") do |path| + next if File.directory?(path) + if File.exists?(path) + File.open(path, "r", encoding: "utf-8", invalid: :skip) do |file| + last_endpoint = Endpoint.new("", "") + file.each_line.with_index do |line, index| + endpoint = line_to_endpoint(line) + if endpoint.method != "" + details = Details.new(PathInfo.new(path, index + 1)) + endpoint.set_details(details) + result << endpoint + last_endpoint = endpoint + end + + param = line_to_param(line) + if param.name != "" + if last_endpoint.method != "" + last_endpoint.push_param(param) + end + end + end + end + end + end + rescue e + # TODO + end + + result + end + + def express_get_endpoint(line : String) + api_path = "" + splited = line.split("(") + if splited.size > 0 + api_path = splited[1].split(",")[0].gsub(/['"]/, "") + end + + api_path + end + + def line_to_param(line : String) : Param + if line.includes? "req.body." + param = line.split("req.body.")[1].split(")")[0].split("}")[0].split(";")[0] + return Param.new(param, "", "json") + end + + if line.includes? "req.query." + param = line.split("req.query.")[1].split(")")[0].split("}")[0].split(";")[0] + return Param.new(param, "", "query") + end + + if line.includes? "req.cookies." + param = line.split("req.cookies.")[1].split(")")[0].split("}")[0].split(";")[0] + return Param.new(param, "", "cookie") + end + + if line.includes? "req.header(" + param = line.split("req.header(")[1].split(")")[0].gsub(/['"]/, "") + return Param.new(param, "", "header") + end + + Param.new("", "", "") + end + + def line_to_endpoint(line : String) : Endpoint + if line.includes? ".get('/" + api_path = express_get_endpoint(line) + if api_path != "" + return Endpoint.new(api_path, "GET") + end + end + if line.includes? ".post('/" + api_path = express_get_endpoint(line) + if api_path != "" + return Endpoint.new(api_path, "POST") + end + end + if line.includes? ".put('/" + api_path = express_get_endpoint(line) + if api_path != "" + return Endpoint.new(api_path, "PUT") + end + end + if line.includes? ".delete('/" + api_path = express_get_endpoint(line) + if api_path != "" + return Endpoint.new(api_path, "DELETE") + end + end + if line.includes? ".patch('/" + api_path = express_get_endpoint(line) + if api_path != "" + return Endpoint.new(api_path, "PATCH") + end + end + + Endpoint.new("", "") + end +end + +def analyzer_restify(options : Hash(Symbol, String)) + instance = AnalyzerRestify.new(options) + instance.analyze +end diff --git a/src/detector/detector.cr b/src/detector/detector.cr index 37bcf29..33e27fc 100644 --- a/src/detector/detector.cr +++ b/src/detector/detector.cr @@ -27,6 +27,7 @@ def detect_techs(base_path : String, options : Hash(Symbol, String), logger : No DetectorJavaJsp, DetectorJavaSpring, DetectorJsExpress, + DetectorJsRestify, DetectorKotlinSpring, DetectorOas2, DetectorOas3, diff --git a/src/detector/detectors/js_restify.cr b/src/detector/detectors/js_restify.cr new file mode 100644 index 0000000..eea22a9 --- /dev/null +++ b/src/detector/detectors/js_restify.cr @@ -0,0 +1,21 @@ +require "../../models/detector" + +class DetectorJsRestify < Detector + def detect(filename : String, file_contents : String) : Bool + if (filename.includes? ".js") && (file_contents.includes? "require('restify')") + true + elsif (filename.includes? ".js") && (file_contents.includes? "require(\"restify\")") + true + elsif (filename.includes? ".ts") && (file_contents.includes? "server") + true + elsif (filename.includes? ".ts") && (file_contents.includes? "require(\"restify\")") + true + else + false + end + end + + def set_name + @name = "js_restify" + end +end diff --git a/src/techs/techs.cr b/src/techs/techs.cr index ea543b8..a835fb1 100644 --- a/src/techs/techs.cr +++ b/src/techs/techs.cr @@ -59,6 +59,11 @@ module NoirTechs :language => "JavaScript", :similar => ["express", "js-express", "js_express"], }, + :js_restify => { + :framework => "Restify", + :language => "JavaScript", + :similar => ["restify", "js-restify"], + }, :kotlin_spring => { :framework => "Spring", :language => "Kotlin",