presence 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.simplecov +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +22 -0
- data/bin/presence_scan +21 -0
- data/lib/presence/commands.rb +18 -0
- data/lib/presence/errors.rb +7 -0
- data/lib/presence/listeners/logger.rb +65 -0
- data/lib/presence/listeners/mac_list.rb +15 -0
- data/lib/presence/listeners/mac_printer.rb +9 -0
- data/lib/presence/listeners/nmapper.rb +23 -0
- data/lib/presence/listeners/tracker.rb +53 -0
- data/lib/presence/scanner.rb +108 -0
- data/lib/presence/version.rb +3 -0
- data/lib/presence.rb +9 -0
- data/presence.gemspec +26 -0
- data/spec/presence/scanner_spec.rb +94 -0
- data/spec/spec_helper.rb +18 -0
- metadata +133 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.simplecov
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class SimpleCov::Formatter::QualityFormatter
|
2
|
+
def format(result)
|
3
|
+
SimpleCov::Formatter::HTMLFormatter.new.format(result)
|
4
|
+
File.open('coverage/covered_percent', 'w') do |f|
|
5
|
+
f.puts result.source_files.covered_percent.to_f
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
SimpleCov.formatter = SimpleCov::Formatter::QualityFormatter
|
10
|
+
|
11
|
+
SimpleCov.start do
|
12
|
+
add_filter '/spec/'
|
13
|
+
add_group 'CLI', 'lib/duple/cli'
|
14
|
+
end
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Jason Wadsworth
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Presence
|
2
|
+
|
3
|
+
Monitors the local network for presence of network clients by MAC address.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Install arping (Mac OS X)
|
8
|
+
|
9
|
+
$ brew install arping
|
10
|
+
|
11
|
+
Install arping (Debian/Ubuntu)
|
12
|
+
|
13
|
+
$ sudo apt-get install arping
|
14
|
+
|
15
|
+
Install the gem
|
16
|
+
|
17
|
+
$ gem install presence
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'cane/rake_task'
|
10
|
+
|
11
|
+
desc "Run cane to check quality metrics"
|
12
|
+
Cane::RakeTask.new(:cane) do |cane|
|
13
|
+
cane.abc_max = 15
|
14
|
+
cane.style_measure = 100
|
15
|
+
cane.style_glob = '{lib}/**/*.rb'
|
16
|
+
cane.gte = {'coverage/covered_percent' => 50}
|
17
|
+
end
|
18
|
+
rescue LoadError
|
19
|
+
warn "cane not available, quality task not provided."
|
20
|
+
end
|
21
|
+
|
22
|
+
task :default => [:spec, :cane]
|
data/bin/presence_scan
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
if File.exists?(File.join(File.expand_path('../..', __FILE__), '.git'))
|
6
|
+
lib_path = File.expand_path('../../lib', __FILE__)
|
7
|
+
$:.unshift(lib_path)
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'presence'
|
11
|
+
# Presence::CLI::Root.start
|
12
|
+
|
13
|
+
# s = Presence::Scanner.new
|
14
|
+
# s.register_listener(Presence::Logger.new)
|
15
|
+
# s.register_listener(Presence::Tracker.new)
|
16
|
+
# s.scan
|
17
|
+
|
18
|
+
Presence::Scanner.scan_loop do |s|
|
19
|
+
s.register_listener(Presence::Logger.new)
|
20
|
+
s.register_listener(Presence::Tracker.new)
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Presence
|
2
|
+
# Wrapper class for shell command execution.
|
3
|
+
class Commands
|
4
|
+
def arping(ip)
|
5
|
+
result = run("sudo arping -c 1 #{ip}")
|
6
|
+
[cmd, result]
|
7
|
+
end
|
8
|
+
|
9
|
+
def local_ip
|
10
|
+
result = run('ifconfig | grep broadcast')
|
11
|
+
result.scan(/[\d\.]+/).first
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(command)
|
15
|
+
`#{command}`
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module Presence
|
2
|
+
# Raised when the presence command is executed in an unsupported environment.
|
3
|
+
class InvalidEnvironment < StandardError; end
|
4
|
+
|
5
|
+
# Raised when an invalid listener is registered with the Presence::Scanner.
|
6
|
+
class InvalidListener < StandardError; end
|
7
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Presence
|
4
|
+
# Scanner listener that sends descriptions of scan events to a log. By
|
5
|
+
# default, it uses a Logger instance that writes to stdout. To enable more
|
6
|
+
# verbose output, set:
|
7
|
+
#
|
8
|
+
# logger.level = ::Logger::INFO
|
9
|
+
#
|
10
|
+
# or:
|
11
|
+
#
|
12
|
+
# logger.level = ::Logger::DEBUG
|
13
|
+
#
|
14
|
+
# To write to a file or some other outlet, pass an instance of Logger to the
|
15
|
+
# constructor.
|
16
|
+
class Logger
|
17
|
+
attr_accessor :logger
|
18
|
+
|
19
|
+
def initialize(log = nil)
|
20
|
+
if log.nil?
|
21
|
+
log = ::Logger.new(STDOUT)
|
22
|
+
log.level = ::Logger::WARN
|
23
|
+
log.formatter = proc do |severity, datetime, progname, msg|
|
24
|
+
"#{msg}\n"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
self.logger = log
|
28
|
+
end
|
29
|
+
|
30
|
+
def listener_registered(listener, scanner)
|
31
|
+
logger.info "Registered listener: <#{listener.class}> for: #{scanner}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def scan_started(ip_prefix, range)
|
35
|
+
logger.info "Checking range: #{ip_prefix}.#{range.first} to #{ip_prefix}.#{range.last}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def scan_finished(ip_prefix, range)
|
39
|
+
logger.info "Scan finished."
|
40
|
+
end
|
41
|
+
|
42
|
+
def ip_scanned(ip, cmd, result)
|
43
|
+
logger.debug " - Checked #{ip} with #{cmd}"
|
44
|
+
result.split("\n").each do |l|
|
45
|
+
logger.debug " #{l}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def localhost_found(ip, mac)
|
50
|
+
logger.debug " * Found localhost!"
|
51
|
+
end
|
52
|
+
|
53
|
+
def mac_found(ip, mac)
|
54
|
+
logger.debug
|
55
|
+
logger.debug " * Found #{mac} at #{ip}"
|
56
|
+
logger.debug
|
57
|
+
end
|
58
|
+
|
59
|
+
def mac_not_found(ip)
|
60
|
+
logger.debug
|
61
|
+
logger.debug " * No MAC found at #{ip}"
|
62
|
+
logger.debug
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Presence
|
2
|
+
# Scanner listener that stores a hash of MAC address to IP address for all
|
3
|
+
# MACs found by the scanner.
|
4
|
+
class MACList
|
5
|
+
attr_accessor :macs_found
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@macs_found = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def mac_found(ip, mac)
|
12
|
+
@macs_found[mac] = ip
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Presence
|
2
|
+
|
3
|
+
# Scanner listener that executes and prints the output from nmap for all MACs
|
4
|
+
# found by the scanner.
|
5
|
+
class NMapper
|
6
|
+
def localhost_found(ip, mac)
|
7
|
+
@local_ip = ip
|
8
|
+
@local_mac = mac
|
9
|
+
end
|
10
|
+
|
11
|
+
def mac_found(ip, mac)
|
12
|
+
return if ip == @local_ip
|
13
|
+
|
14
|
+
result = `sudo nmap -O #{ip}`
|
15
|
+
puts '*' * 50
|
16
|
+
puts "* IP: #{ip}"
|
17
|
+
result.split("\n").each do |l|
|
18
|
+
puts " #{l}"
|
19
|
+
end
|
20
|
+
puts '*' * 50
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'presence/listeners/mac_list'
|
2
|
+
|
3
|
+
module Presence
|
4
|
+
|
5
|
+
# Scanner listener that tracks all MACs found by the scanner. This listener is
|
6
|
+
# intended to be used when scanning in a loop. The tracker will maintain a
|
7
|
+
# list of MAC addresses on the network and detect when a new client connects
|
8
|
+
# or when a connected client disconnects.
|
9
|
+
class Tracker
|
10
|
+
def initialize
|
11
|
+
@mac_history = {}
|
12
|
+
@current_list = Presence::MACList.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def listener_registered(l, scanner)
|
16
|
+
scanner.register_listener(@current_list) if l == self
|
17
|
+
end
|
18
|
+
|
19
|
+
def mac_found(ip, mac)
|
20
|
+
if @mac_history[mac].nil?
|
21
|
+
mac_connected(mac, ip)
|
22
|
+
elsif @mac_history[mac] != ip
|
23
|
+
mac_changed(mac, @mac_history[mac], ip)
|
24
|
+
end
|
25
|
+
@mac_history[mac] = ip
|
26
|
+
end
|
27
|
+
|
28
|
+
def scan_finished(ip_prefix, range)
|
29
|
+
macs_left = @mac_history.keys - @current_list.macs_found.keys
|
30
|
+
macs_left.each do |mac|
|
31
|
+
old_ip = @mac_history[mac]
|
32
|
+
mac_disconnected(mac, old_ip)
|
33
|
+
@mac_history.delete(mac)
|
34
|
+
end
|
35
|
+
@current_list.macs_found.clear
|
36
|
+
end
|
37
|
+
|
38
|
+
def mac_connected(mac, ip)
|
39
|
+
puts " ** #{mac} connected as #{ip}"
|
40
|
+
# Do something interesting.
|
41
|
+
end
|
42
|
+
|
43
|
+
def mac_changed(mac, old_ip, new_ip)
|
44
|
+
puts " ** #{mac} changed ip from: #{old_ip} to #{new_ip}"
|
45
|
+
# Do something interesting.
|
46
|
+
end
|
47
|
+
|
48
|
+
def mac_disconnected(mac, old_ip)
|
49
|
+
puts " ** #{mac} disconnected from #{old_ip}"
|
50
|
+
# Do something interesting.
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'presence/errors'
|
2
|
+
|
3
|
+
module Presence
|
4
|
+
|
5
|
+
# Scans a network for connected clients, captures the MAC address, and
|
6
|
+
# dispatches related events to any registered listeners.
|
7
|
+
class Scanner
|
8
|
+
PAIR = '[0-9a-f]{2}'
|
9
|
+
SEP = '\:'
|
10
|
+
MAC_REGEXP = Regexp.new("(#{6.times.map {PAIR}.join(SEP)})")
|
11
|
+
|
12
|
+
attr_accessor :listeners, :options
|
13
|
+
|
14
|
+
def initialize(options = nil)
|
15
|
+
options ||= {}
|
16
|
+
self.options = {
|
17
|
+
ip_prefix: nil,
|
18
|
+
octet_range: (1..255)
|
19
|
+
}.merge(options)
|
20
|
+
self.listeners = []
|
21
|
+
@commands = Presence::Commands.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def register_listener(l)
|
25
|
+
raise Presence::InvalidListener.new("Listener cannot be nil") if l.nil?
|
26
|
+
listeners << l
|
27
|
+
dispatch(:listener_registered, l, self)
|
28
|
+
end
|
29
|
+
|
30
|
+
def localhost_ip
|
31
|
+
unless @localhost_ip
|
32
|
+
@localhost_ip = @commands.local_ip
|
33
|
+
end
|
34
|
+
@localhost_ip
|
35
|
+
end
|
36
|
+
|
37
|
+
def ip_prefix
|
38
|
+
unless options[:ip_prefix]
|
39
|
+
options[:ip_prefix] = localhost_ip.split('.')[0,3].join('.')
|
40
|
+
end
|
41
|
+
options[:ip_prefix]
|
42
|
+
end
|
43
|
+
|
44
|
+
def octet_range
|
45
|
+
options[:octet_range]
|
46
|
+
end
|
47
|
+
|
48
|
+
def scan
|
49
|
+
dispatch(:scan_started, ip_prefix, octet_range)
|
50
|
+
octet_range.each do |i|
|
51
|
+
scan_ip("#{ip_prefix}.#{i}")
|
52
|
+
end
|
53
|
+
dispatch(:scan_finished, ip_prefix, octet_range)
|
54
|
+
end
|
55
|
+
|
56
|
+
def scan_ip(ip)
|
57
|
+
cmd, result = @commands.arping(ip)
|
58
|
+
dispatch(:ip_scanned, ip, cmd, result)
|
59
|
+
process_scan_result(ip, cmd, result)
|
60
|
+
end
|
61
|
+
|
62
|
+
def process_scan_result(ip, cmd, result)
|
63
|
+
if result =~ MAC_REGEXP
|
64
|
+
mac = $1
|
65
|
+
dispatch(:localhost_found, ip, mac) if ip == localhost_ip
|
66
|
+
dispatch(:mac_found, ip, mac)
|
67
|
+
else
|
68
|
+
dispatch(:mac_not_found, ip)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def dispatch(event, *args)
|
73
|
+
listeners.each do |l|
|
74
|
+
l.send(event, *args) if l.respond_to?(event)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_s
|
79
|
+
"<#{self.class} ip_prefix: '#{self.ip_prefix}' octet_range: (#{self.octet_range})>"
|
80
|
+
end
|
81
|
+
|
82
|
+
class << self
|
83
|
+
def check_env
|
84
|
+
commands = Commands.new
|
85
|
+
if commands.run('which ifconfig').size == 0
|
86
|
+
raise Presence::InvalidEnvironment.new("Unsupported platform: ifconfig not found.")
|
87
|
+
end
|
88
|
+
if commands.run('which arping').size == 0
|
89
|
+
raise Presence::InvalidEnvironment.new("Unsupported platform: arping not found.")
|
90
|
+
raise Presence::InvalidEnvironment.new("Install arping first: brew install arping")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def scan_loop(&block)
|
95
|
+
scanner = self.new
|
96
|
+
yield(scanner) if block_given?
|
97
|
+
|
98
|
+
while(true)
|
99
|
+
begin
|
100
|
+
scanner.scan
|
101
|
+
rescue Interrupt
|
102
|
+
break
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/presence.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'presence/version'
|
2
|
+
require 'presence/errors'
|
3
|
+
require 'presence/commands'
|
4
|
+
require 'presence/scanner'
|
5
|
+
require 'presence/listeners/logger'
|
6
|
+
require 'presence/listeners/mac_list'
|
7
|
+
require 'presence/listeners/mac_printer'
|
8
|
+
require 'presence/listeners/nmapper'
|
9
|
+
require 'presence/listeners/tracker'
|
data/presence.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'presence/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "presence"
|
8
|
+
gem.version = Presence::VERSION
|
9
|
+
gem.authors = ["Jason Wadsworth"]
|
10
|
+
gem.email = ["jdwadsworth@gmail.com"]
|
11
|
+
gem.description = %q{Monitors the local network for presence of network clients by MAC address.}
|
12
|
+
gem.summary = %q{Plays theme music when d8:d1:cb:b3:af:c4 arrives.}
|
13
|
+
gem.homepage = "https://github.com/subakva/presence"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
# gem.add_dependency('thor')
|
21
|
+
|
22
|
+
gem.add_development_dependency('rake', ['~> 0.9.2'])
|
23
|
+
gem.add_development_dependency('rspec', ['~> 2.11.0'])
|
24
|
+
gem.add_development_dependency('cane', ['~> 2.3.0'])
|
25
|
+
gem.add_development_dependency('simplecov', ['~> 0.7.1'])
|
26
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Presence::Scanner do
|
4
|
+
let(:local_ip) { '10.0.1.30' }
|
5
|
+
let(:local_mac) { '8d:1d:bc:3b:fa:4c' }
|
6
|
+
|
7
|
+
let(:ip) { '10.0.1.31' }
|
8
|
+
let(:mac) { 'd8:d1:cb:b3:af:c4' }
|
9
|
+
let(:arping_cmd) { "sudo arping -c 1 #{ip}" }
|
10
|
+
|
11
|
+
let(:commands) {
|
12
|
+
commands = stub(Presence::Commands)
|
13
|
+
Presence::Commands.should_receive(:new).and_return(commands)
|
14
|
+
commands
|
15
|
+
}
|
16
|
+
let(:listener) {
|
17
|
+
listener = mock(Object)
|
18
|
+
scanner.register_listener(listener)
|
19
|
+
listener
|
20
|
+
}
|
21
|
+
let(:octet_range) { (30..32) }
|
22
|
+
let(:scanner) { Presence::Scanner.new(octet_range: octet_range) }
|
23
|
+
|
24
|
+
before {
|
25
|
+
commands.stub(:local_ip).and_return(local_ip)
|
26
|
+
commands.stub(:arping).and_return([arping_cmd, 'No such jeaun'])
|
27
|
+
commands.stub(:arping).with(local_ip).and_return([arping_cmd, local_mac])
|
28
|
+
commands.stub(:arping).with(ip).and_return([arping_cmd, mac])
|
29
|
+
}
|
30
|
+
|
31
|
+
describe '#scan' do
|
32
|
+
it 'dispatches a scan_started event' do
|
33
|
+
listener.should_receive(:scan_started).with('10.0.1', octet_range)
|
34
|
+
scanner.scan
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'dispatches a scan_finished event' do
|
38
|
+
listener.should_receive(:scan_finished).with('10.0.1', octet_range)
|
39
|
+
scanner.scan
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'scans all IPs in the range' do
|
43
|
+
listener.should_receive(:ip_scanned).with('10.0.1.30', arping_cmd, local_mac)
|
44
|
+
listener.should_receive(:ip_scanned).with('10.0.1.31', arping_cmd, mac)
|
45
|
+
listener.should_receive(:ip_scanned).with('10.0.1.32', arping_cmd, 'No such jeaun')
|
46
|
+
scanner.scan
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#scan_ip' do
|
51
|
+
it 'executes arping to check for a mac address' do
|
52
|
+
commands.should_receive(:arping).with(ip).and_return([arping_cmd, mac])
|
53
|
+
scanner.scan_ip(ip)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'dispatches an ip_scanned event' do
|
57
|
+
listener.should_receive(:ip_scanned).with(ip, arping_cmd, mac)
|
58
|
+
scanner.scan_ip(ip)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'dispatches a mac_found event' do
|
62
|
+
listener.should_receive(:mac_found).with(ip, mac)
|
63
|
+
scanner.scan_ip(ip)
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'with a localhost IP' do
|
67
|
+
it 'dispatches a localhost_found event' do
|
68
|
+
listener.should_receive(:localhost_found).with(local_ip, local_mac)
|
69
|
+
scanner.scan_ip(local_ip)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with a non-existent IP' do
|
74
|
+
before {
|
75
|
+
commands.stub(:arping).with(ip).and_return([arping_cmd, 'No such jeaun'])
|
76
|
+
}
|
77
|
+
|
78
|
+
it 'does not dispatch a mac_found event' do
|
79
|
+
listener.should_not_receive(:mac_found)
|
80
|
+
scanner.scan_ip(ip)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'dispatches an ip_scanned event' do
|
84
|
+
listener.should_receive(:ip_scanned).with(ip, arping_cmd, 'No such jeaun')
|
85
|
+
scanner.scan_ip(ip)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'dispatches a mac_not_found event' do
|
89
|
+
listener.should_receive(:mac_not_found).with(ip)
|
90
|
+
scanner.scan_ip(ip)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
lib_path = File.expand_path('../../lib', __FILE__)
|
2
|
+
$:.unshift(lib_path)
|
3
|
+
|
4
|
+
require 'simplecov'
|
5
|
+
require 'presence'
|
6
|
+
Dir['spec/support/**/*.rb'].each { |f| require File.expand_path(f) }
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.filter_run :focus
|
12
|
+
|
13
|
+
# Run specs in random order to surface order dependencies. If you find an
|
14
|
+
# order dependency and want to debug it, you can fix the order by providing
|
15
|
+
# the seed, which is printed after each run.
|
16
|
+
# --seed 1234
|
17
|
+
config.order = 'random'
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: presence
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jason Wadsworth
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
prerelease: false
|
16
|
+
type: :development
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.9.2
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: 0.9.2
|
29
|
+
name: rake
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
prerelease: false
|
32
|
+
type: :development
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 2.11.0
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 2.11.0
|
45
|
+
name: rspec
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
prerelease: false
|
48
|
+
type: :development
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.3.0
|
55
|
+
version_requirements: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 2.3.0
|
61
|
+
name: cane
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
prerelease: false
|
64
|
+
type: :development
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ~>
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 0.7.1
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 0.7.1
|
77
|
+
name: simplecov
|
78
|
+
description: Monitors the local network for presence of network clients by MAC address.
|
79
|
+
email:
|
80
|
+
- jdwadsworth@gmail.com
|
81
|
+
executables:
|
82
|
+
- presence_scan
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- .rspec
|
88
|
+
- .simplecov
|
89
|
+
- Gemfile
|
90
|
+
- LICENSE.txt
|
91
|
+
- README.md
|
92
|
+
- Rakefile
|
93
|
+
- bin/presence_scan
|
94
|
+
- lib/presence.rb
|
95
|
+
- lib/presence/commands.rb
|
96
|
+
- lib/presence/errors.rb
|
97
|
+
- lib/presence/listeners/logger.rb
|
98
|
+
- lib/presence/listeners/mac_list.rb
|
99
|
+
- lib/presence/listeners/mac_printer.rb
|
100
|
+
- lib/presence/listeners/nmapper.rb
|
101
|
+
- lib/presence/listeners/tracker.rb
|
102
|
+
- lib/presence/scanner.rb
|
103
|
+
- lib/presence/version.rb
|
104
|
+
- presence.gemspec
|
105
|
+
- spec/presence/scanner_spec.rb
|
106
|
+
- spec/spec_helper.rb
|
107
|
+
homepage: https://github.com/subakva/presence
|
108
|
+
licenses: []
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 1.8.23
|
128
|
+
signing_key:
|
129
|
+
specification_version: 3
|
130
|
+
summary: Plays theme music when d8:d1:cb:b3:af:c4 arrives.
|
131
|
+
test_files:
|
132
|
+
- spec/presence/scanner_spec.rb
|
133
|
+
- spec/spec_helper.rb
|