Skip to content

Commit

Permalink
Merge pull request #16 from jclusso/lookup_via_url
Browse files Browse the repository at this point in the history
Add ability to lookup via URL
  • Loading branch information
jclusso authored Feb 25, 2024
2 parents 7e37676 + 975a1a6 commit 5774e66
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 16 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ group :test do
# Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
gem "capybara"
gem "selenium-webdriver"
gem "faker"
end

gem "tailwindcss-rails", "~> 2.3"
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ GEM
drb (2.2.0)
ruby2_keywords
erubi (1.12.0)
faker (3.2.3)
i18n (>= 1.8.11, < 2)
globalid (1.2.1)
activesupport (>= 6.1)
i18n (1.14.1)
Expand Down Expand Up @@ -315,6 +317,7 @@ DEPENDENCIES
debug
dnsruby
dockerfile-rails (>= 1.6)
faker
importmap-rails
minitest-retry
pg (~> 1.5)
Expand Down
5 changes: 2 additions & 3 deletions app/controllers/queries_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def index
end.order(created_at: :desc)

@query = Query.new(@queries.first&.slice(:type, :server))
@limit = params[:limit].to_i.clamp(25, 500)
end

def show
Expand All @@ -21,9 +22,7 @@ def create
@query.session_id = session.id.to_s

if @query.valid?
dns_lookup = DNSLookup.new(@query.server_ip)
@query.results = dns_lookup.run(@query.domain, @query.type)
@query.duration = dns_lookup.duration
@query.do_dns_lookup!
@query.save

redirect_to @query
Expand Down
23 changes: 23 additions & 0 deletions app/controllers/redirect_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class RedirectController < ApplicationController

def create
if params[:domain_name].present?
query = Query.new(params.permit(:server, :type, :domain_name))
query.type ||= 'A'
query.server ||= 'Cloudflare'
query.session_id = session.id.to_s

if query.valid?
query.do_dns_lookup!
query.save

redirect_to query_path(query)
else
redirect_to root_path
end
else
redirect_to root_path
end
end

end
25 changes: 20 additions & 5 deletions app/models/query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,26 @@ def domain=(value)
return unless value.present?

value.gsub!(/(^\w+:|^)\/\//, '') # remove protocols
value.gsub!(/\/.+/, '') # remove path
value.gsub!(/\/(?:[^\/]|\/(?!$))*$/, '') # remove path
value.delete!(' ') # remove any spaces
value.downcase!

super(value)
end
alias_method :domain_name=, :domain=

def server=(value)
ip = self.class.servers[value.to_sym]
return unless ip
server_hash = self.class.servers.find do |name, ip|
name.to_s.downcase == value.downcase
end
return unless server_hash

super(value)
self.server_ip = ip
super(server_hash.first)
self.server_ip = server_hash.last
end

def type=(value)
value.upcase!
return unless self.class.types.include?(value)

super(value)
Expand All @@ -72,4 +76,15 @@ def duration_ms
"#{(duration || 0).to_fs(:delimited)} ms"
end

def do_dns_lookup!
dns_lookup = DNSLookup.new(server_ip)
self.results = dns_lookup.run(domain, type)
self.duration = dns_lookup.duration
self
end

def redirect_params
{ domain_name: domain, type: type.downcase, server: server.downcase }
end

end
2 changes: 1 addition & 1 deletion app/views/queries/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</tr>
</thead>
<tbody class="divide-y divide-neutral-800">
<%= render @queries.limit(25) %>
<%= render @queries.limit(@limit) %>
</tbody>
</table>
</div>
Expand Down
17 changes: 15 additions & 2 deletions app/views/queries/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<span><%= @query.duration_ms %></span>
</div>
</div>

<%= turbo_frame_tag :results, class: "block bg-black p-4 rounded-lg sm:text-lg border-2 border-neutral-800 overflow-hidden" do %>
<%
def button_classes(button)
Expand All @@ -39,13 +40,25 @@
<% end %>
</div>
<% if @query.results.key?('zone') && @view == 'zone' %>
<pre data-controller="highlight" class="mt-1 opacity-0 transition"><code class="language-dns"><%= @query.results['zone'] %></code></pre>
<pre data-controller="highlight" data-highlight-server-value="<%= @query.server.downcase %>" class="mt-1 opacity-0 transition"><code class="language-dns"><%= @query.results['zone'] %></code></pre>
<% else %>
<pre data-controller="highlight" class="mt-1 opacity-0 transition"><code class="language-json"><%= JSON.pretty_generate(@query.results['json'] || @query.results) %></code></pre>
<pre data-controller="highlight" data-highlight-server-value="<%= @query.server.downcase %>" class="mt-1 opacity-0 transition"><code class="language-json"><%= JSON.pretty_generate(@query.results['json'] || @query.results) %></code></pre>
<% end %>
</div>
<% end %>

<div class="grid grid-cols-1 gap-3 bg-black p-4 rounded-lg sm:text-lg border-2 border-neutral-800">
<div class="flex flex-col">
<span class="text-lime-500 font-semibold">This Lookup</span>
<%= text_field_tag :query, query_url(@query), class: "form-field__input mt-2", readonly: true, onclick: "this.select();" %>
</div>
<div class="flex flex-col">
<span class="text-lime-500 font-semibold">Realtime Lookup</span>
<%= text_field_tag :realtime_query, redirect_url(@query.redirect_params), class: "form-field__input mt-2", readonly: true, onclick: "this.select();" %>
</div>
</div>
</div>

<div class="flex p-4 text-xs text-neutral-600 justify-between">
<% if @query.session_id == session.id.to_s %>
<%= button_to "Remove", query_path(@query), method: :delete,
Expand Down
2 changes: 2 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ class Application < Rails::Application
#
config.time_zone = "Eastern Time (US & Canada)"
# config.eager_load_paths << Rails.root.join("extras")

config.action_view.field_error_proc = ->(html_tag, instance) { html_tag }
end
end
3 changes: 3 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@
# Defines the root path route ("/")
root "queries#index"
resources :queries, only: %i[index create show destroy]

get "((:server)/:type)/:domain_name" => "redirect#create",
constraints: { domain_name: /([^\/]+?)(?=\.json|\.html|$|\/)/ }, as: :redirect
end
5 changes: 3 additions & 2 deletions test/controllers/queries_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ class QueriesControllerTest < ActionDispatch::IntegrationTest
end

test "should create query" do
domain = Faker::Internet.unique.domain_name
assert_difference("Query.count") do
post queries_url, params: {
query: { domain: 'create-google.com', server: 'Cloudflare', type: 'A' }
query: { domain: domain, server: 'Cloudflare', type: 'A' }
}
end

assert_redirected_to query_url(Query.find_by(domain: 'create-google.com'))
assert_redirected_to query_url(Query.find_by(domain: domain))
end

test "should show query" do
Expand Down
40 changes: 40 additions & 0 deletions test/controllers/redirect_controller_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require "test_helper"

class RedirectControllerTest < ActionDispatch::IntegrationTest
setup do
@domain = Faker::Internet.unique.domain_name
end

test "should create query with server, type, and domain" do
get "/google/mx/#{@domain}"

assert_redirected_to query_path(new_query)
assert_equal 'Google', new_query.server
assert_equal 'MX', new_query.type
assert_equal @domain, new_query.domain
end

test "should create query with type and domain" do
get "/mx/#{@domain}"

assert_redirected_to query_path(new_query)
assert_equal 'Cloudflare', new_query.server
assert_equal 'MX', new_query.type
assert_equal @domain, new_query.domain
end

test "should create query with domain" do
get "/#{@domain}"

assert_redirected_to query_path(new_query)
assert_equal 'Cloudflare', new_query.server
assert_equal 'A', new_query.type
assert_equal @domain, new_query.domain
end

private

def new_query
@new_query ||= Query.find_by(domain: @domain)
end
end
56 changes: 53 additions & 3 deletions test/models/query_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,57 @@
require "test_helper"

class QueryTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
test "domain setter will strip paths" do
query = Query.new(domain: 'd53.com/path')
assert_equal 'd53.com', query.domain
end

test "domain setter will strip just a trailing slash" do
query = Query.new(domain: 'd53.com/')
assert_equal 'd53.com', query.domain
end

test "domain setter will strip protocols" do
query1 = Query.new(domain: 'http://d53.com')
query2 = Query.new(domain: 'ftp://d53.com')
assert_equal 'd53.com', query1.domain
assert_equal 'd53.com', query2.domain
end

test "domain setter will strip spaces" do
query = Query.new(domain: 'd53 .com')
assert_equal 'd53.com', query.domain
end

test "domain setter will strip protocol, path, and spaces togather" do
query = Query.new(domain: 'http://d53.com/this path')
assert_equal 'd53.com', query.domain
end

test "server setter will only set known server" do
query_with_known_server = Query.new(server: 'Cloudflare')
query_with_unknown_server = Query.new(server: 'Flarecloud')

assert_equal 'Cloudflare', query_with_known_server.server
assert_equal '1.1.1.1', query_with_known_server.server_ip
assert_nil query_with_unknown_server.server
assert_nil query_with_unknown_server.server_ip
end

test "server setter is case insensitive" do
query = Query.new(server: 'cloudflare')
assert_equal 'Cloudflare', query.server
end

test "type setter will only set known type" do
query_with_known_type = Query.new(type: 'A')
query_with_unknown_type = Query.new(type: 'B')
assert_equal 'A', query_with_known_type.type
assert_nil query_with_unknown_type.type
end

test "type setter is case insensitive" do
query = Query.new(type: 'a')
assert_equal 'A', query.type
end
end

0 comments on commit 5774e66

Please sign in to comment.