Validate website ownership in rails

ruby-on-rails

Solution

This is is how you could validate a domain using the google subdomain approach in a RESTful style. You will allow a user to create a Site record, which will remain unverified until the user later clicks a link/button to verify the domain at a later time (to allow DNS propagation).

This code is untested but will get you started.

Model:

class Site < ActiveRecord::Base
  # schema
  # create_table "sites", :force => true do |t|
  #  t.string   "domain"
  #  t.string   "cname"
  #  t.integer  "user_id"
  #  t.boolean  "verified"
  #  t.datetime "created_at"
  #  t.datetime "updated_at"
  # end

  require "resolv"

  YOUR_DOMAIN = "example.com"

  belongs_to :user
  before_create :generate_cname

  attr_accessible :domain
  …

  # Validate unless already validated
  def validate!
    validate_cname unless self.verifed == true
  end

  protected

  # Generate a random string for cname
  def generate_cname
    chars = ('a'..'z').to_a
    self.cname = 10.times.collect { chars[rand(chars.length)] }.join
  end

  # Sets verifed to true if there is a CNAME record matching the cname attr and it points to this site.
  def validate_cname
    Resolv::DNS.open do |domain|
      @dns = domain.getresources("#{cname}.#{domain}", Resolv::DNS::Resource::IN::CNAME)
     self.verified = !@dns.empty? && @dns.first.name.to_s == YOUR_DOMAIN
    end
  end

end

Controller

class SitesController < ActionController::Base
  # Usual RESTful controller actions
  # …

  def validate
    @site = current_user.sites.find(params[:id])
    @site.validate!

    respond_to do |format|
      if @site.save && @site.verified
        flash[:notice] = 'Site verified!'
        format.html { redirect_to(@site) }
        format.xml  { head :ok }
      else
        flash[:Error] = 'Site verification failed!'
        format.html { redirect_to(@site) }
        format.xml  { render :status => :unprocessable_entity }
      end
    end

  end
end

Put this in routes.rb:

map.resources :sites, :member => { :validate => :put }

I'll leave implementing the views as an exercise for you.

Problem

For a more recent discussion about a similar topic check this question out. What's the best way to validate whether a particular user has ownership of a website? Let's say you had this model: ``` class User < ActiveRecord::Base has_many :websites end ``` In order to make sure the User does indeed own that website I thought about doing email validations. Example: user lists example.com as their website and an email gets sent to username@example.com. If a user sends a response message from example.com the website is validate. The problem with this is if there was a website where a large group of people could send an email from a website with that domain name, like gmail.com. I wouldn't want a user to register gmail as their personal website. Thus it seems the best way to do it is to have the user to embed some code in the HTML and the rails applications makes sure that that code is there. How would you go about doing this?

Original source