Page Menu
Home
GRNET
Search
Configure Global Search
Log In
Files
F1969604
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, May 17, 10:30 AM
Size
11 KB
Mime Type
text/x-diff
Expires
Tue, May 19, 10:30 AM (12 h, 17 m)
Engine
blob
Format
Raw Data
Handle
385181
Attached To
rWEBDNS WebDNS (edet4)
View Options
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 8761224..fd70334 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,34 +1,39 @@
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
attr_writer :breadcrumb
+ helper_method :admin?
+
+ def admin?
+ params.key?(:admin)
+ end
private
def group
@group ||= domain.group
end
def domain
@domain ||= domain_scope.find(params[:domain_id] || params[:id])
end
def record
@record ||= record_scope.find(params[:record_id] || params[:id])
end
def group_scope
@group_scope ||= Group.all
end
def domain_scope
@domain_scope ||= Domain.where(group: group_scope)
end
def record_scope
@record_scope ||= domain.records
end
end
diff --git a/app/controllers/records_controller.rb b/app/controllers/records_controller.rb
index 2c8a1c0..60f7046 100644
--- a/app/controllers/records_controller.rb
+++ b/app/controllers/records_controller.rb
@@ -1,49 +1,53 @@
class RecordsController < ApplicationController
before_action :domain
before_action :record, only: [:edit, :update, :destroy]
# GET /records/new
def new
@record = domain.records.build
end
# GET /records/1/edit
def edit
end
# POST /records
def create
@record = domain.records.new(new_record_params)
if @record.save
redirect_to domain, notice: 'Record was successfully created.'
else
render :new
end
end
# PATCH/PUT /records/1
def update
if @record.update(edit_record_params)
redirect_to domain, notice: 'Record was successfully updated.'
else
render :edit
end
end
# DELETE /records/1
def destroy
@record.destroy
redirect_to domain, notice: 'Record was successfully destroyed.'
end
private
def edit_record_params
- params.require(:record).permit(:name, :content, :prio, :disabled)
+ params.require(:record).permit(:name, :content, :prio, :disabled).tap { |r|
+ r[:drop_privileges] = true if not admin?
+ }
end
def new_record_params
- params.require(:record).permit(:name, :content, :type, :prio)
+ params.require(:record).permit(:name, :content, :type, :prio).tap { |r|
+ r[:drop_privileges] = true if not admin?
+ }
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index de6be79..876d94e 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1,2 +1,8 @@
module ApplicationHelper
+ def can_edit?(object)
+ return true if admin?
+ return true unless object.respond_to?(:editable?)
+
+ object.editable?
+ end
end
diff --git a/app/models/record.rb b/app/models/record.rb
index 9fe1d27..912eb05 100644
--- a/app/models/record.rb
+++ b/app/models/record.rb
@@ -1,75 +1,100 @@
require 'ipaddr'
+require_dependency 'drop_privileges_validator'
class Record < ActiveRecord::Base
belongs_to :domain
def self.record_types
[
'SOA', 'NS', 'CNAME',
'A', 'AAAA',
'MX',
'TXT', 'SPF', 'SRV', 'SSHFP',
'PTR',
]
end
+ def self.allowed_record_types
+ record_types - WebDNS.settings[:prohibit_records_types]
+ end
+
validates :name, presence: true
validates :type, inclusion: { in: record_types }
+ # Don't allow the following actions on drop privileges mode
+ validates_drop_privileges :type,
+ message: 'You cannot touch that record!',
+ unless: -> { Record.allowed_record_types.include?(type) }
+ validates_drop_privileges :name,
+ message: 'You cannot touch top level NS records!',
+ if: -> { type == 'NS' && domain_record? }
+
before_validation :guess_reverse_name
before_validation :set_name
after_save :update_zone_serial
after_destroy :update_zone_serial
def short
return '' if name == domain.name
return '' if name.blank?
File.basename(name, ".#{domain.name}")
end
+ def domain_record?
+ name.blank? || name == domain.name
+ end
+
+ # Editable by a non-admin user
+ def editable?
+ return false unless Record.allowed_record_types.include?(type)
+ return false if type == 'NS' && domain_record?
+
+ true
+ end
+
def supports_prio?
false
end
# Create record specific urls for all record types
#
# Overrides default rails STI
def self.model_name
return super if self == Record
Record.model_name
end
def to_dns
[name, 'IN', type, supports_prio? ? prio : nil, content].compact.join(' ')
end
private
# Hooks
def guess_reverse_name
return if not type == 'PTR'
return if not domain.reverse?
return if name.blank?
reverse = IPAddr.new(name).reverse
self.name = reverse if reverse.end_with?(domain.name)
rescue IPAddr::InvalidAddressError # rubycop:disable HandleExceptions
end
# Powerdns expects full domain names
def set_name
self.name = domain.name if name.blank?
self.name = "#{name}.#{domain.name}" if not name.end_with?(domain.name)
end
def update_zone_serial
# SOA records handle serial themselves
return true if type == 'SOA'
domain.soa.bump_serial!
end
end
diff --git a/app/views/domains/show.html.erb b/app/views/domains/show.html.erb
index ec738f4..e866df0 100644
--- a/app/views/domains/show.html.erb
+++ b/app/views/domains/show.html.erb
@@ -1,31 +1,37 @@
<table class="table table-striped table-hover">
<thead>
<tr>
<th colspan="5">Records</th>
<th colspan="3">Controls</th>
</tr>
</thead>
<tbody>
<% @domain.records.each do |record| %>
<tr class="<%= record.disabled? ? 'warning' : '' %>">
<td><%= record.name %></td>
<td>IN</td>
<td><%= record.type %></td>
<td><%= record.supports_prio? ? record.prio : '' %></td>
<td><%= record.content %></td>
- <td>
- <% if record.disabled? %>
- <%= link_to 'Enable', enable_domain_record_path(@domain, record), method: :put %>
- <% else %>
- <%= link_to 'Disable', disable_domain_record_path(@domain, record), method: :put %>
- <% end %>
- </td>
- <td><%= link_to 'Edit', edit_domain_record_path(@domain, record) %></td>
- <td><%= link_to 'Remove', [@domain, record], method: :delete, data: { confirm: 'Are you sure?' } %></td>
+ <% if can_edit?(record) %>
+ <td>
+ <% if record.disabled? %>
+ <%= link_to 'Enable', enable_domain_record_path(@domain, record), method: :put %>
+ <% else %>
+ <%= link_to 'Disable', disable_domain_record_path(@domain, record), method: :put %>
+ <% end %>
+ </td>
+ <td><%= link_to 'Edit', edit_domain_record_path(@domain, record) if can_edit?(record) %></td>
+ <td><%= link_to 'Remove', [@domain, record], method: :delete, data: { confirm: 'Are you sure?' } %></td>
+ <% else %>
+ <td/>
+ <td/>
+ <td/>
+ <% end %>
</tr>
<% end %>
</tbody>
</table>
<p><%= link_to 'New Record', new_domain_record_path(@domain) %></p>
diff --git a/app/views/records/_form.html.erb b/app/views/records/_form.html.erb
index 418f2ba..93c1fa7 100644
--- a/app/views/records/_form.html.erb
+++ b/app/views/records/_form.html.erb
@@ -1,14 +1,14 @@
<%= bootstrap_form_for([@domain, @record], layout: :horizontal, label_col: 'col-sm-2', control_col: 'col-sm-8') do |f| %>
<%= f.text_field :name, value: @record.short, label: 'Record', append: name_field_append(@record) %>
<% if @record.persisted? %>
<%= f.static_control :type %>
<% else %>
- <%= f.select :type, Record.record_types %>
+ <%= f.select :type, Record.allowed_record_types %>
<% end %>
<%= f.text_field :prio, placeholder: 10, wrapper_class: @record.supports_prio? ? '' : 'hidden' %>
<%= f.text_field :content %>
<%= f.submit 'Save', class: 'btn btn-primary col-sm-offset-2' %>
<% end %>
diff --git a/config/initializers/00_settings.rb b/config/initializers/00_settings.rb
index 88695d4..c6bf360 100644
--- a/config/initializers/00_settings.rb
+++ b/config/initializers/00_settings.rb
@@ -1,13 +1,16 @@
WebDNS = Base
WebDNS.settings[:soa_defaults] = {
primary_ns: 'ns.example.com',
contact: 'domainmaster@example.com',
serial: 1,
refresh: 10_800,
retry: 3600,
expire: 604_800,
nx: 3600
}
WebDNS.settings[:serial_strategy] = Strategies::Date
+
+# Don't allow to create SOA records
+WebDNS.settings[:prohibit_records_types] = ['SOA']
diff --git a/test/models/ns_test.rb b/test/models/ns_test.rb
index a099692..6d81be5 100644
--- a/test/models/ns_test.rb
+++ b/test/models/ns_test.rb
@@ -1,14 +1,29 @@
require 'test_helper'
class NSTest < ActiveSupport::TestCase
setup do
@record = build(:ns)
end
test 'save' do
@record.save
assert_empty @record.errors
end
+ test 'drop privileges on zone NS records' do
+ @record.drop_privileges = true
+ @record.save
+
+ assert_not_empty @record.errors[:name]
+ end
+
+ test 'doesnt drop privileges on non zone NS records' do
+ @record.name = 'other'
+ @record.drop_privileges = true
+
+ @record.save
+
+ assert_empty @record.errors[:name]
+ end
end
diff --git a/test/models/soa_test.rb b/test/models/soa_test.rb
index a96a30f..4096ca2 100644
--- a/test/models/soa_test.rb
+++ b/test/models/soa_test.rb
@@ -1,60 +1,69 @@
require 'test_helper'
class SOATest < ActiveSupport::TestCase
def setup
domain = create(:domain)
@record = domain.soa
end
test 'bump_serial!' do
@record.save!
assert_serial_update @record do
@record.bump_serial!
end
end
test 'updating attributes bumps serial' do
@record.save!
assert_serial_update @record do
@record.contact = 'admin@example.com'
@record.save!
end
end
+ test 'drop privileges' do
+ @record.contact = 'admin@example.com'
+ @record.drop_privileges = true
+ assert_not @record.editable?
+
+ @record.save
+ assert_not_empty @record.errors[:type]
+ end
+
class DateSerialTests < ActiveSupport::TestCase
setup do
domain = create(:date_domain)
@record = domain.soa
end
test 'last bump of the day' do
assert_equal Strategies::Date, @record.domain.serial_strategy
freeze_time do
last_for_day = Time.now.strftime('%Y%m%d99').to_i
@record.serial = last_for_day
@record.save!
assert_serial_update @record do
@record.bump_serial!
end
end
end
test 'existing serial points to a future date' do
assert_equal Strategies::Date, @record.domain.serial_strategy
freeze_time do
future_day = (Time.now + 1.week).strftime('%Y%m%d00').to_i
@record.serial = future_day
@record.save!
assert_serial_update @record do
@record.bump_serial!
end
end
end
end
end
Event Timeline
Log In to Comment