diff --git a/app/assets/javascripts/pamela.js.coffee b/app/assets/javascripts/pamela.js.coffee new file mode 100644 index 0000000..7615679 --- /dev/null +++ b/app/assets/javascripts/pamela.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/stylesheets/pamela.css.scss b/app/assets/stylesheets/pamela.css.scss new file mode 100644 index 0000000..1f2fc52 --- /dev/null +++ b/app/assets/stylesheets/pamela.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the pamela controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/pamela_controller.rb b/app/controllers/pamela_controller.rb new file mode 100644 index 0000000..f47115e --- /dev/null +++ b/app/controllers/pamela_controller.rb @@ -0,0 +1,189 @@ +class PamelaController < ApplicationController + +#require "active_record" +require "optparse" +#require "rubygems" + +def index + @macs = Mac.all +end + + # GET /macs/1 + # GET /macs/1.json + def show + @mac = Mac.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.json { render :json => @macs } + end + end + + # GET /macs/new + # GET /macs/new.json + def new + @mac = Mac.new + @users = User.all.sort_by(&:name) + + respond_to do |format| + format.html # new.html.erb + format.json { render :json => @mac } + end + end + + # GET /macs/1/edit + def edit + @mac = Mac.find(params[:id]) + @users = User.all.sort_by(&:name) + end + + # POST /macs + # POST /user + def create + @mac = Mac.new(params[:mac]) + + respond_to do |format| + if @mac.save + format.html { redirect_to "/pamela", :notice => 'Mac was successfully created.' } + format.json { render :json => @mac, :status => :created, :location => @mac } + else + format.html { render :action => "new" } + format.json { render :json => @mac.errors, :status => :unprocessable_entity } + end + end + end + + # PUT /macs/1 + # PUT /macs/1.json + def update + #Log who updated this + @mac = Mac.find(params[:id]) + + respond_to do |format| + if @mac.update_attributes(params[:mac]) + format.html { redirect_to "/pamela", :notice => 'User certification was successfully updated.' } + format.json { head :no_content } + else + format.html { render :action => "edit" } + format.json { render :json => @mac.errors, :status => :unprocessable_entity } + end + end + end + + + +def scan +Rails.logger.info "starting scan..." + # Command line arguments + options = {}; + OptionParser.new { |opts| + opts.banner = "Usage: pamela-scanner.rb --interface=en0" + + options[:verbose] = true + opts.on("v", "--verbose", "Run verbosely") { |verbose| + options[:verbose] = verbose + } + + options[:interface] = "eth0" + opts.on("i", "--interface=interface", "Network Interface") { |interface| + options[:interface] = interface + } + + options[:max_age] = 20 + opts.on("a", "--max-age=minutes", "Minutes to keep expired macs active") { |max_age| + options[:max_age] = max_age.to_i + } + + options[:db_host] = "configure_me" + opts.on("r", "--db-host=host", "Database Host") { |host| + options[:db_host] = host + } + + options[:db_name] = "configure_me" + opts.on("n", "--db-name=name", "Database Name") { |name| + options[:db_name] = name + } + + options[:db_user] = "configure_me" + opts.on("u", "--db-user=user", "Database User") { |user| + options[:db_user] = user + } + + options[:db_password] = "configure_me" + opts.on("p", "--db-password=password", "Database Password") { |password| + options[:db_password] = password + } + + }.parse! + + # Open the database + #ActiveRecord::Base::establish_connection( + # :adapter => "mysql2", + # :host => options[:db_host], + # :database => options[:db_name], + # :username => options[:db_user], + # :password => options[:db_password]) + + #class Mac < ActiveRecord::Base + #end + + #class MacLog < ActiveRecord::Base + #end + + # Scan the network for mac addresses + macs = {}; + command = sprintf("arp-scan -R --interface=%s --localnet", options[:interface]) + if options[:verbose] + Rails.logger.info "Running [#{command}]" + end + IO.popen(command) { |stdin| + Rails.logger.info "Reading stdin: "+stdin.inspect + stdin.each { |line| + next if line !~ /^([\d\.]+)\s+([[:xdigit:]:]+)\s/; + macs[$2] = $1; + } + } + + # Scan the existing macs and update each record as necessary + Mac.find(:all).each { |entry| + Rails.logger.info "Existing MAC: "+entry.inspect + mac = entry.mac + ip = entry.ip + if macs.has_key?(mac) + if ! entry.active || ! entry.since + Rails.logger.info "Activating #{mac} at #{ip}" if options[:verbose] + entry.since = Time.now + MacLog.new(:mac => mac, :ip => ip, :action => "activate").save + end + entry.active = 1 + entry.ip = ip + entry.refreshed = Time.now + entry.save + macs.delete(mac) + next + end + + # Entry is no longer current + if entry.active + ageMinutes = ((Time.now - entry.refreshed)/60).to_i + next if ageMinutes < options[:max_age] + Rails.logger.info "Deactivating #{mac}, #{ageMinutes} minutes old" if options[:verbose] + entry.active = 0 + entry.save + MacLog.new(:mac => mac, :ip => ip, :action => "deactivate").save + end + } + + # Add entries for any macs not already in the db + macs.each { |mac, ip| + Rails.logger.info "Activating new entry #{mac} at #{ip}" if options[:verbose] + Mac.new(:mac => mac, :ip => ip, :active => 1, :since => Time.now, :refreshed => Time.now).save + MacLog.new(:mac => mac, :ip => ip, :action => "activate").save + } + +@log = MacLog.all + +end #def scan + + +end diff --git a/app/helpers/pamela_helper.rb b/app/helpers/pamela_helper.rb new file mode 100644 index 0000000..c42e8a9 --- /dev/null +++ b/app/helpers/pamela_helper.rb @@ -0,0 +1,2 @@ +module PamelaHelper +end diff --git a/app/models/mac.rb b/app/models/mac.rb new file mode 100644 index 0000000..fe3c903 --- /dev/null +++ b/app/models/mac.rb @@ -0,0 +1,4 @@ +class Mac < ActiveRecord::Base + belongs_to :user + attr_accessible :active, :ip, :mac, :refreshed, :since +end diff --git a/app/models/mac_log.rb b/app/models/mac_log.rb new file mode 100644 index 0000000..142c825 --- /dev/null +++ b/app/models/mac_log.rb @@ -0,0 +1,3 @@ +class MacLog < ActiveRecord::Base + attr_accessible :action, :ip, :mac +end diff --git a/app/views/pamela/_form.html.erb b/app/views/pamela/_form.html.erb new file mode 100644 index 0000000..9759232 --- /dev/null +++ b/app/views/pamela/_form.html.erb @@ -0,0 +1,25 @@ +<%= form_for(@mac) do |f| %> + <% if @mac.errors.any? %> +
+

<%= pluralize(@mac.errors.count, "error") %> prohibited this Mac from being saved:

+ + +
+ <% end %> + +
+ <%= f.label :user_id, "User" %>
+ <%= collection_select(:mac, :user_id, @users, :id, :name) %> +
+
+ <%= f.label :mac, "Mac" %>
+ <%= f.text_field :mac %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/pamela/edit.html.erb b/app/views/pamela/edit.html.erb new file mode 100644 index 0000000..bad1ee6 --- /dev/null +++ b/app/views/pamela/edit.html.erb @@ -0,0 +1,6 @@ +

Editing User Certification

+ +<%= render 'form' %> + +<%= link_to 'Show', @user_certification %> | +<%= link_to 'Back', user_certifications_path %> diff --git a/app/views/pamela/index.html.erb b/app/views/pamela/index.html.erb new file mode 100644 index 0000000..1762fe7 --- /dev/null +++ b/app/views/pamela/index.html.erb @@ -0,0 +1,9 @@ +

What machines are on our network?

+<% @macs.each do |mac| %> + <%= mac.user.name unless mac.user.blank? %> + <%= mac.mac %> | + <%= link_to 'Edit', edit_mac_path(mac) %>
+<% end %> diff --git a/app/views/pamela/new.html.erb b/app/views/pamela/new.html.erb new file mode 100644 index 0000000..e2d36ae --- /dev/null +++ b/app/views/pamela/new.html.erb @@ -0,0 +1,5 @@ +

New User Certification

+ +<%= render 'form' %> + +<%= link_to 'Back', user_certifications_path %> diff --git a/app/views/pamela/scan.html.erb b/app/views/pamela/scan.html.erb new file mode 100644 index 0000000..5068661 --- /dev/null +++ b/app/views/pamela/scan.html.erb @@ -0,0 +1,5 @@ +Scanning... +<% @log.each do |log| %> + <%= log.mac %> = + <%= log.ip %>
+<% end %> diff --git a/config/routes.rb b/config/routes.rb index 2030948..04288db 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -27,6 +27,15 @@ Dooraccess::Application.routes.draw do match 'door_logs/download' => 'door_logs#download', :as => :download match 'door_logs/auto_download' => 'door_logs#auto_download', :as => :auto_download + match 'pamela/scan' => 'pamela#scan' + match 'pamela' => 'pamela#index', :as => :macs + match 'pamela/:id' => 'pamela#show', :as => :mac + match 'pamela/:id/edit' => 'pamela#edit', :as => :edit_mac + put 'pamela/:id' => 'pamela#update' #PUT + match 'pamela/new' => 'pamela#new', :as => :new_mac + post 'pamela' => 'pamela#create' #POST + + root :to => "home#index" # The priority is based upon order of creation: diff --git a/db/migrate/20130201021949_create_macs.rb b/db/migrate/20130201021949_create_macs.rb new file mode 100644 index 0000000..eda0f31 --- /dev/null +++ b/db/migrate/20130201021949_create_macs.rb @@ -0,0 +1,15 @@ +class CreateMacs < ActiveRecord::Migration + def change + create_table :macs do |t| + t.references :user + t.string :mac + t.string :ip + t.datetime :since + t.datetime :refreshed + t.boolean :active + + t.timestamps + end + add_index :macs, :user_id + end +end diff --git a/db/migrate/20130201022153_create_mac_logs.rb b/db/migrate/20130201022153_create_mac_logs.rb new file mode 100644 index 0000000..8024312 --- /dev/null +++ b/db/migrate/20130201022153_create_mac_logs.rb @@ -0,0 +1,11 @@ +class CreateMacLogs < ActiveRecord::Migration + def change + create_table :mac_logs do |t| + t.string :mac + t.string :ip + t.string :action + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 95a78b0..148d575 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130125185724) do +ActiveRecord::Schema.define(:version => 20130201022153) do create_table "cards", :force => true do |t| t.string "card_number" @@ -35,6 +35,27 @@ ActiveRecord::Schema.define(:version => 20130125185724) do t.datetime "updated_at", :null => false end + create_table "mac_logs", :force => true do |t| + t.string "mac" + t.string "ip" + t.string "action" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "macs", :force => true do |t| + t.integer "user_id" + t.string "mac" + t.string "ip" + t.datetime "since" + t.datetime "refreshed" + t.boolean "active" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "macs", ["user_id"], :name => "index_macs_on_user_id" + create_table "user_certifications", :force => true do |t| t.integer "user_id" t.integer "certification_id" diff --git a/test/fixtures/mac_logs.yml b/test/fixtures/mac_logs.yml new file mode 100644 index 0000000..60572c7 --- /dev/null +++ b/test/fixtures/mac_logs.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html + +one: + mac: MyString + ip: MyString + action: MyString + +two: + mac: MyString + ip: MyString + action: MyString diff --git a/test/fixtures/macs.yml b/test/fixtures/macs.yml new file mode 100644 index 0000000..07768ac --- /dev/null +++ b/test/fixtures/macs.yml @@ -0,0 +1,17 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html + +one: + user: + mac: MyString + ip: MyString + since: 2013-01-31 19:19:49 + refreshed: 2013-01-31 19:19:49 + active: false + +two: + user: + mac: MyString + ip: MyString + since: 2013-01-31 19:19:49 + refreshed: 2013-01-31 19:19:49 + active: false diff --git a/test/functional/pamela_controller_test.rb b/test/functional/pamela_controller_test.rb new file mode 100644 index 0000000..62411af --- /dev/null +++ b/test/functional/pamela_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class PamelaControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/helpers/pamela_helper_test.rb b/test/unit/helpers/pamela_helper_test.rb new file mode 100644 index 0000000..cf7bbeb --- /dev/null +++ b/test/unit/helpers/pamela_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class PamelaHelperTest < ActionView::TestCase +end diff --git a/test/unit/mac_log_test.rb b/test/unit/mac_log_test.rb new file mode 100644 index 0000000..579ba01 --- /dev/null +++ b/test/unit/mac_log_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class MacLogTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/mac_test.rb b/test/unit/mac_test.rb new file mode 100644 index 0000000..f4c998c --- /dev/null +++ b/test/unit/mac_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class MacTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end