Skip to content

Instantly share code, notes, and snippets.

@bf4
Last active February 18, 2018 18:07
Show Gist options
  • Save bf4/5320631 to your computer and use it in GitHub Desktop.
Save bf4/5320631 to your computer and use it in GitHub Desktop.
Rails Router
<% if Rails.env.development? || Subdomain.new.internal_ip_user?(request) %>
More verbose errors
<% end %>
Rails.application.routes.draw do
# create these routes only for in-office or vpn users
scope :constraints => Subdomain.new do
get '/restricted'=> 'foo#internal'
# if the admin subdomain is enabled in application.yml
if Subdomain.use_admin_subdomain?
# if not on the admin subdomain
scope :constraints => { :host => /\A[^a]/o } do
# is redirected to the admin subdomain
match '(*any)' => redirect { |p, request|
request.url.sub(request.host, [Subdomain.admin, request.domain].join('.'))
}
end
# if on the admin subdomain
scope :constraints => { :subdomain => Subdomain.admin } do
end
end
end
get '/unrestricted'=> 'foo#external'
root :to => "home#index"
# See how all your routes lay out with "rake routes".
get '/401' => 'Pages::Errors#unauthorized'
get '/404' => 'Pages::Errors#not_found'
get '/422' => 'Pages::Errors#rejected_change'
get '/500' => 'Pages::Errors#error'
end
Rails.application.config.session_store ActionDispatch::Session::CacheStore, :expire_after => 20.minutes, :domain => :all
# instead of domain: :all, you may change top level domain size if necessary, e.g. for example.co.uk
# request.domain(2)
# request.subdomain(2)
class Subdomain
def initialize(options={})
@default_valid_subdomains = options[:valid_subdomains]
@ips = office_external_ips + office_internal_ips
end
def matches?(request)
ip = remote_ip(request)
request_subdomain = request.subdomain
set_valid_subdomains(request_subdomain)
not_production? || (ip_in_range?(ip) && valid_subdomain?(request_subdomain))
end
def self.admin
'admin'
end
def self.use_admin_subdomain?
!!(ENV['USE_ADMIN_SUBDOMAIN'] =~ /true/i)
end
def self.admin_helper
if use_admin_subdomain?
{:subdomain => admin }
else
{}
end
end
def internal_ip_user?(request)
ip = remote_ip(request)
ip_in_range?(ip)
end
private
def not_production?
!Rails.env.production?
end
def ip_in_range?(ip)
@ips.include?(ip)
end
def valid_subdomain?(subdomain)
@valid_subdomains.any? {|sub| sub == subdomain }
end
def ip_range(net,subnet_range)
subnet_range.map {|sub| "#{net}.#{sub}" }
end
def office_external_ips
ip_range("200.90.100",(1..126))
end
def office_internal_ips
['127.0.0.1'] +
ip_range("192.168.168",(0..255))
end
def remote_ip(request)
request.headers['HTTP_X_REAL_IP'] || request.remote_ip
end
def set_valid_subdomains(request_subdomain)
@valid_subdomains = Array(@default_valid_subdomains || request_subdomain)
end
end
class SubdomainController < ApplicationController
include UrlHelper
protect_from_forgery
def can_register_admin
internal_request?
end
private
def internal_request?
Subdomain.new.matches?(request)
end
end
require File.expand_path('../../../lib/subdomain', __FILE__)
require 'active_support/core_ext/string'
describe Subdomain do
let(:request) { OpenStruct.new(:remote_ip => '', :subdomain => '', :headers => {}) }
let(:external_ip) { '200.90.100.10' }
let(:internal_ip) { '192.168.168.1' }
let(:foreign_ip) { '8.8.8.8' }
describe "when in production, matches" do
['www','admin','foo',''].each do |sub|
it "an external ip on subdomain #{sub.inspect}" do
subdomain = Subdomain.new
subdomain.stub(:not_production?).and_return(false)
request.remote_ip = external_ip
request.subdomain = sub
subdomain.matches?(request).should be_true
end
it "an internal ip on subdomain #{sub.inspect}" do
subdomain = Subdomain.new
subdomain.stub(:not_production?).and_return(false)
request.remote_ip = internal_ip
request.subdomain = sub
subdomain.matches?(request).should be_true
end
context "only the specified subdomains" do
it "an external ip on subdomain #{sub.inspect}" do
subdomain = Subdomain.new(:valid_subdomains => ['admin'])
subdomain.stub(:not_production?).and_return(false)
request.remote_ip = external_ip
request.subdomain = sub
subdomain.matches?(request).should == (sub == 'admin')
end
it "an internal ip on subdomain #{sub.inspect}" do
subdomain = Subdomain.new(:valid_subdomains => ['admin'])
subdomain.stub(:not_production?).and_return(false)
request.remote_ip = internal_ip
request.subdomain = sub
admin_domain = (sub == 'admin')
subdomain.matches?(request).should == (sub == 'admin')
end
end
end
it "based on the real ip" do
subdomain = Subdomain.new(:valid_subdomains => ['admin'])
subdomain.stub(:not_production?).and_return(false)
request.remote_ip = '127.0.0.1'
request.subdomain = 'admin'
request.headers['HTTP_X_REAL_IP'] = external_ip
subdomain.matches?(request).should be_true
end
end
describe "when in production, does not matches on" do
['www','admin','foo',''].each do |sub|
it "a foreign ip on subdomain #{sub.inspect}" do
subdomain = Subdomain.new
subdomain.stub(:not_production?).and_return(false)
request.remote_ip = foreign_ip
request.subdomain = sub
subdomain.matches?(request).should be_false
end
end
it "based on the real ip" do
subdomain = Subdomain.new(:valid_subdomains => ['admin'])
subdomain.stub(:not_production?).and_return(false)
request.remote_ip = '127.0.0.1'
request.subdomain = 'admin'
request.headers['HTTP_X_REAL_IP'] = foreign_ip
subdomain.matches?(request).should be_false
end
end
describe "when NOT in production, matches all requests" do
['www','admin','foo',''].each do |sub|
it "an external ip on subdomain #{sub.inspect}" do
subdomain = Subdomain.new
subdomain.stub(:not_production?).and_return(true)
request.remote_ip = external_ip
request.subdomain = sub
subdomain.matches?(request).should be_true
end
it "an internal ip on subdomain #{sub.inspect}" do
subdomain = Subdomain.new
subdomain.stub(:not_production?).and_return(true)
request.remote_ip = internal_ip
request.subdomain = sub
subdomain.matches?(request).should be_true
end
it "another ip on subdomain #{sub.inspect}" do
subdomain = Subdomain.new
subdomain.stub(:not_production?).and_return(true)
request.remote_ip = foreign_ip
request.subdomain = sub
subdomain.matches?(request).should be_true
end
end
end
end
# from http://railscasts.com/episodes/221-subdomains-in-rails-3
# use as e.g.
# link_to blog.name, root_url(:subdomain => blog.subdomain)
# link_to "All Blogs", root_url(:subdomain => false)
# link_to 'Admin', admin_root_path(Subdomain.admin_helper)
module UrlHelper
def with_subdomain(subdomain)
subdomain = (subdomain || "")
subdomain += "." unless subdomain.empty?
[subdomain, request.domain].join
end
def url_for(options = nil)
if options.kind_of?(Hash) && options.has_key?(:subdomain)
options[:host] = with_subdomain(options.delete(:subdomain))
end
super
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment