sheepsafe 0.1.0
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/History.txt +4 -0
- data/LICENSE +21 -0
- data/README.md +73 -0
- data/Rakefile +104 -0
- data/bin/sheepsafe +18 -0
- data/doc/add-untrusted-apply.jpg +0 -0
- data/doc/edit-locations.jpg +0 -0
- data/lib/sheepsafe.rb +9 -0
- data/lib/sheepsafe/config.rb +36 -0
- data/lib/sheepsafe/controller.rb +89 -0
- data/lib/sheepsafe/installer.rb +153 -0
- data/lib/sheepsafe/network.rb +25 -0
- data/lib/sheepsafe/status.rb +14 -0
- data/sheepsafe.gemspec +67 -0
- data/spec/sheepsafe_spec.rb +127 -0
- metadata +149 -0
data/History.txt
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2010 Nick Sieger
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
Sheepsafe
|
2
|
+
=========
|
3
|
+
|
4
|
+
http://github.com/nicksieger/sheepsafe
|
5
|
+
|
6
|
+
## Description
|
7
|
+
|
8
|
+
Sheepsafe is a small utility to keep you safe from [FireSheep][]!
|
9
|
+
|
10
|
+
Sheepsafe was built to automate the task of switching your network
|
11
|
+
configuration to use a SOCKS proxy whenever you join an untrusted
|
12
|
+
network.
|
13
|
+
|
14
|
+
Sheepsafe works by keeping a configuration of known safe wireless
|
15
|
+
networks. When you join an untrusted network, Sheepsafe switches to a
|
16
|
+
network location that has a SOCKS proxy configured and starts a SOCKS
|
17
|
+
proxy by SSH'ing into a remote server, thus protecting your browsing
|
18
|
+
traffic from FireSheep and other snoopers on the local network. When
|
19
|
+
you switch back to a safe network, Sheepsafe switches back to the
|
20
|
+
default, trusted location and shuts down the SOCKS proxy.
|
21
|
+
|
22
|
+
You could probably use something like [Marco Polo][polo] for this too,
|
23
|
+
but this setup Works For Me.
|
24
|
+
|
25
|
+
## Requirements
|
26
|
+
|
27
|
+
- Mac OS X. That's what I run. You'll have to cook something else up
|
28
|
+
for a different OS. Tested on 10.6.
|
29
|
+
- An SSH account on a remote server that can serve as a SOCKS proxy
|
30
|
+
through which to tunnel traffic. Typically this can be an EC2
|
31
|
+
server, a VPS, or some other cloud instance.
|
32
|
+
- Ruby 1.8.7 or greater. The Mac OS X system-installed Ruby is
|
33
|
+
preferred as the OS will be launching Sheepsafe in the background.
|
34
|
+
|
35
|
+
## Install
|
36
|
+
|
37
|
+
- First install the gem: `sudo gem install sheepsafe`. It's
|
38
|
+
recommended to install using the system Ruby to minimize
|
39
|
+
difficulties informing launchd about an [RVM][] or some other
|
40
|
+
package manager.
|
41
|
+
- After installing the gem, run `sheepsafe install` and follow the
|
42
|
+
prompts for configuring Sheepsafe.
|
43
|
+
|
44
|
+
### Setting up the "Untrusted" location
|
45
|
+
|
46
|
+
One manual step that you need to do during installation is to create
|
47
|
+
an "Untrusted" location for Sheepsafe to configure and use when you're
|
48
|
+
on an untrusted network. Sheepsafe will prompt you to do these steps
|
49
|
+
during installation.
|
50
|
+
|
51
|
+

|
52
|
+
|
53
|
+

|
54
|
+
|
55
|
+
## Growl
|
56
|
+
|
57
|
+
If you wish to receive Growl notifications when Sheepsafe is switching
|
58
|
+
your location, be sure to install the `growlnotify` utility from the
|
59
|
+
"Extras" folder in the Growl .dmg.
|
60
|
+
|
61
|
+
## Post-install
|
62
|
+
|
63
|
+
Be sure you configure your applications to use system-wide proxy
|
64
|
+
settings for making connections, where applicable.
|
65
|
+
|
66
|
+
## Uninstall
|
67
|
+
|
68
|
+
- Run `sheepsafe uninstall` to unregister the Launchd task and remove
|
69
|
+
Sheepsafe vestiges from your system.
|
70
|
+
|
71
|
+
[FireSheep]: http://codebutler.com/firesheep
|
72
|
+
[RVM]: http://rvm.beginrescueend.com/
|
73
|
+
[polo]: http://www.symonds.id.au/marcopolo/
|
data/Rakefile
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'rake/clean'
|
3
|
+
|
4
|
+
#############################################################################
|
5
|
+
#
|
6
|
+
# Helper functions
|
7
|
+
#
|
8
|
+
#############################################################################
|
9
|
+
|
10
|
+
def name
|
11
|
+
@name ||= Dir['*.gemspec'].first.split('.').first
|
12
|
+
end
|
13
|
+
|
14
|
+
def version
|
15
|
+
line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
|
16
|
+
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
17
|
+
end
|
18
|
+
|
19
|
+
def date
|
20
|
+
Date.today.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
def rubyforge_project
|
24
|
+
"jruby-extras"
|
25
|
+
end
|
26
|
+
|
27
|
+
def gemspec_file
|
28
|
+
"#{name}.gemspec"
|
29
|
+
end
|
30
|
+
|
31
|
+
def gem_file
|
32
|
+
"#{name}-#{version}*.gem"
|
33
|
+
end
|
34
|
+
|
35
|
+
def replace_header(head, header_name)
|
36
|
+
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
|
37
|
+
end
|
38
|
+
|
39
|
+
#############################################################################
|
40
|
+
#
|
41
|
+
# Standard tasks
|
42
|
+
#
|
43
|
+
#############################################################################
|
44
|
+
|
45
|
+
task :default => :spec
|
46
|
+
|
47
|
+
require 'rspec/core/rake_task'
|
48
|
+
RSpec::Core::RakeTask.new do |t|
|
49
|
+
end
|
50
|
+
|
51
|
+
require 'rake/rdoctask'
|
52
|
+
Rake::RDocTask.new do |rdoc|
|
53
|
+
rdoc.rdoc_dir = 'rdoc'
|
54
|
+
rdoc.title = "#{name} #{version}"
|
55
|
+
rdoc.rdoc_files.include('README*')
|
56
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
57
|
+
end
|
58
|
+
|
59
|
+
task :release => :build do
|
60
|
+
unless `git branch` =~ /^\* master$/
|
61
|
+
puts "You must be on the master branch to release!"
|
62
|
+
exit!
|
63
|
+
end
|
64
|
+
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
65
|
+
sh "git tag v#{version}"
|
66
|
+
sh "git push origin master"
|
67
|
+
sh "git push origin v#{version}"
|
68
|
+
sh "gem push pkg/#{name}-#{version}.gem"
|
69
|
+
end
|
70
|
+
|
71
|
+
task :build => :gemspec do
|
72
|
+
sh "mkdir -p pkg"
|
73
|
+
sh "gem build #{gemspec_file}"
|
74
|
+
sh "mv #{gem_file} pkg"
|
75
|
+
end
|
76
|
+
CLEAN << 'pkg'
|
77
|
+
|
78
|
+
task :gemspec do
|
79
|
+
# read spec file and split out manifest section
|
80
|
+
spec = File.read(gemspec_file)
|
81
|
+
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
82
|
+
|
83
|
+
# replace name version and date
|
84
|
+
replace_header(head, :name)
|
85
|
+
replace_header(head, :version)
|
86
|
+
replace_header(head, :date)
|
87
|
+
#comment this out if your rubyforge_project has a different name
|
88
|
+
replace_header(head, :rubyforge_project)
|
89
|
+
|
90
|
+
# determine file list from git ls-files
|
91
|
+
files = `git ls-files`.
|
92
|
+
split("\n").
|
93
|
+
sort.
|
94
|
+
reject { |file| file =~ /^\./ }.
|
95
|
+
reject { |file| file =~ /^(rdoc|pkg)/ }.
|
96
|
+
map { |file| " #{file}" }.
|
97
|
+
join("\n")
|
98
|
+
|
99
|
+
# piece file back together and write
|
100
|
+
manifest = " s.files = %w[\n#{files}\n ]\n"
|
101
|
+
spec = [head, manifest, tail].join(" # = MANIFEST =\n")
|
102
|
+
File.open(gemspec_file, 'w') { |io| io.write(spec) }
|
103
|
+
puts "Updated #{gemspec_file}"
|
104
|
+
end
|
data/bin/sheepsafe
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
begin
|
5
|
+
require 'sheepsafe'
|
6
|
+
rescue LoadError
|
7
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
8
|
+
require 'sheepsafe'
|
9
|
+
end
|
10
|
+
|
11
|
+
if ARGV.length == 1 && ARGV.first =~ /^(un)?install$/
|
12
|
+
installer = Sheepsafe::Installer.new
|
13
|
+
ARGV.first == 'install' ? installer.run : installer.uninstall
|
14
|
+
else
|
15
|
+
# Allow network changes to sink in for a couple more seconds
|
16
|
+
sleep 2
|
17
|
+
Sheepsafe::Controller.new.run
|
18
|
+
end
|
Binary file
|
Binary file
|
data/lib/sheepsafe.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Sheepsafe
|
4
|
+
class Config
|
5
|
+
FILE = File.expand_path('~/.sheepsafe.yml')
|
6
|
+
DEFAULT_CONFIG = {"untrusted_location" => "Untrusted", "socks_port" => "9999"}
|
7
|
+
ATTRS = %w(trusted_location untrusted_location last_network ssh_host socks_port)
|
8
|
+
ARRAY_ATTRS = %w(trusted_names)
|
9
|
+
|
10
|
+
def self.load_config
|
11
|
+
File.open(FILE) {|f| YAML.load(f) }
|
12
|
+
rescue
|
13
|
+
raise "Unable to read ~/sheepsafe.yml; please run sheepsafe-install"
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :config
|
17
|
+
|
18
|
+
def initialize(hash = nil)
|
19
|
+
@config = DEFAULT_CONFIG.merge(hash || self.class.load_config)
|
20
|
+
end
|
21
|
+
|
22
|
+
ATTRS.each do |m|
|
23
|
+
define_method(m) { config[m] }
|
24
|
+
define_method("#{m}=") {|v| config[m] = v}
|
25
|
+
end
|
26
|
+
|
27
|
+
ARRAY_ATTRS.each do |m|
|
28
|
+
define_method(m) { config[m] ||= [] }
|
29
|
+
define_method("#{m}=") {|v| config[m] = [v].flatten}
|
30
|
+
end
|
31
|
+
|
32
|
+
def write
|
33
|
+
File.open(FILE, "w") {|f| f << YAML.dump(@config) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'daemons'
|
2
|
+
require 'logger'
|
3
|
+
require 'growl'
|
4
|
+
|
5
|
+
module Sheepsafe
|
6
|
+
class Controller
|
7
|
+
LOG_FILE = Sheepsafe::Config::FILE.sub(/\.yml/, '.log')
|
8
|
+
|
9
|
+
def initialize(config = nil, status = nil, logger = nil)
|
10
|
+
@config = config || Sheepsafe::Config.new
|
11
|
+
@status = status || Sheepsafe::Status.new(@config)
|
12
|
+
@logger = logger || begin
|
13
|
+
STDOUT.reopen(File.open(LOG_FILE, (File::WRONLY | File::APPEND)))
|
14
|
+
Logger.new(STDOUT)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
log("Sheepsafe starting")
|
20
|
+
if network_up?
|
21
|
+
if network_changed?
|
22
|
+
if switch_to_trusted?
|
23
|
+
notify_ok "Switching to #{@config.trusted_location} location"
|
24
|
+
system "scselect #{@config.trusted_location}"
|
25
|
+
bring_socks_proxy 'down'
|
26
|
+
elsif switch_to_untrusted?
|
27
|
+
notify_warning "Switching to #{@config.untrusted_location} location"
|
28
|
+
bring_socks_proxy 'up'
|
29
|
+
system "scselect #{@config.untrusted_location}"
|
30
|
+
end
|
31
|
+
@config.last_network = @status.current_network
|
32
|
+
@config.write
|
33
|
+
end
|
34
|
+
else
|
35
|
+
log("AirPort is off")
|
36
|
+
end
|
37
|
+
log("Sheepsafe finished")
|
38
|
+
end
|
39
|
+
|
40
|
+
def network_up?
|
41
|
+
@status.network_up?
|
42
|
+
end
|
43
|
+
|
44
|
+
def network_changed?
|
45
|
+
@status.current_network != @config.last_network
|
46
|
+
end
|
47
|
+
|
48
|
+
def switch_to_trusted?
|
49
|
+
@status.current_network.trusted?
|
50
|
+
end
|
51
|
+
|
52
|
+
def switch_to_untrusted?
|
53
|
+
!@status.current_network.trusted?
|
54
|
+
end
|
55
|
+
|
56
|
+
def bring_socks_proxy(direction)
|
57
|
+
Daemons.run_proc '.sheepsafe.proxy', :ARGV => [direction == 'up' ? 'start' : 'stop'], :dir_mode => :normal, :dir => ENV['HOME'] do
|
58
|
+
log("Starting ssh -ND #{@config.socks_port} #{@config.ssh_host}")
|
59
|
+
exec("ssh -ND #{@config.socks_port} #{@config.ssh_host}")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def proxy_running?
|
64
|
+
File.exist?("#{ENV['HOME']}/.sheepsafe.proxy.pid")
|
65
|
+
end
|
66
|
+
|
67
|
+
def notify_ok(msg)
|
68
|
+
check_growl_installed
|
69
|
+
Growl.notify_ok(msg)
|
70
|
+
log(msg)
|
71
|
+
end
|
72
|
+
|
73
|
+
def notify_warning(msg)
|
74
|
+
check_growl_installed
|
75
|
+
Growl.notify_warning(msg)
|
76
|
+
log(msg)
|
77
|
+
end
|
78
|
+
|
79
|
+
def check_growl_installed
|
80
|
+
unless Growl.installed?
|
81
|
+
log("WARNING: Growl not installed (probably couldn't find growlnotify in PATH: #{ENV['PATH']})")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def log(msg)
|
86
|
+
@logger.info(msg)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module Sheepsafe
|
2
|
+
class Installer
|
3
|
+
PLIST_FILE = File.expand_path("~/Library/LaunchAgents/sheepsafe.plist")
|
4
|
+
|
5
|
+
attr_reader :config, :status, :controller
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
require 'highline/import'
|
9
|
+
@config = File.readable?(Sheepsafe::Config::FILE) ? Sheepsafe::Config.new : Sheepsafe::Config.new({})
|
10
|
+
@status = Sheepsafe::Status.new(@config)
|
11
|
+
@controller = Sheepsafe::Controller.new @config, @status, Logger.new(Sheepsafe::Controller::LOG_FILE)
|
12
|
+
update_config_with_status
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
intro_message
|
17
|
+
config_prompts
|
18
|
+
manual_network_location_prompt
|
19
|
+
setup_untrusted_location
|
20
|
+
write_config
|
21
|
+
write_launchd_plist
|
22
|
+
register_launchd_task
|
23
|
+
announce_done
|
24
|
+
end
|
25
|
+
|
26
|
+
def intro_message
|
27
|
+
say(<<-MSG)
|
28
|
+
Welcome to Sheepsafe!
|
29
|
+
|
30
|
+
So you want to protect yourself from FireSheep snoopers like me, eh?
|
31
|
+
Follow the prompts to get started.
|
32
|
+
MSG
|
33
|
+
end
|
34
|
+
|
35
|
+
def config_prompts
|
36
|
+
say "First thing we need is the name of a server you can reach via SSH."
|
37
|
+
|
38
|
+
config.ssh_host = ask "SSH connection (server name or user@server) >\n" do |q|
|
39
|
+
q.default = config.ssh_host
|
40
|
+
end
|
41
|
+
|
42
|
+
say "Testing connectivitity to #{config.ssh_host}..."
|
43
|
+
system "ssh #{config.ssh_host} true"
|
44
|
+
unless $?.success?
|
45
|
+
abort "Sorry! that ssh host was no good."
|
46
|
+
end
|
47
|
+
|
48
|
+
config.socks_port = ask "Ok, next we need to pick a port on localhost where the proxy runs >\n" do |q|
|
49
|
+
q.default = config.socks_port || 9999
|
50
|
+
end
|
51
|
+
|
52
|
+
config.trusted_location = ask "Next, a name for the \"trusted\" network location >\n" do |q|
|
53
|
+
q.default = config.trusted_location
|
54
|
+
end
|
55
|
+
|
56
|
+
config.trusted_names = ask "Next, one or more network names (blank line to stop, RET for #{@names.inspect}) >\n" do |q|
|
57
|
+
q.gather = ""
|
58
|
+
end
|
59
|
+
config.trusted_names = @names if config.trusted_names.empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
def manual_network_location_prompt
|
63
|
+
say "Next, I need you to create and switch to the \"Untrusted\" location in Network preferences."
|
64
|
+
system "open /System/Library/PreferencePanes/Network.prefPane"
|
65
|
+
ask "Press ENTER when done."
|
66
|
+
end
|
67
|
+
|
68
|
+
def setup_untrusted_location
|
69
|
+
if agree "Next, I'll set up the SOCKS proxy in the \"Untrusted\" location for you. OK\? (yes/no)\n"
|
70
|
+
system "networksetup -setsocksfirewallproxy AirPort localhost #{config.socks_port}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def write_config
|
75
|
+
say "Saving configuration to #{Sheepsafe::Config::FILE}..."
|
76
|
+
config.write
|
77
|
+
end
|
78
|
+
|
79
|
+
# Write a launchd plist file to .~/Library/LaunchAgents/sheepsafe.plist.
|
80
|
+
#
|
81
|
+
# For details see http://tech.inhelsinki.nl/locationchanger/
|
82
|
+
def write_launchd_plist
|
83
|
+
say "Setting up launchd configuration file #{PLIST_FILE}..."
|
84
|
+
plist = <<-PLIST
|
85
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
86
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
|
87
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
88
|
+
<plist version="1.0">
|
89
|
+
<dict>
|
90
|
+
<key>Label</key>
|
91
|
+
<string>org.rubygems.sheepsafe</string>
|
92
|
+
<key>ProgramArguments</key>
|
93
|
+
<array>
|
94
|
+
<string>#{sheepsafe_bin_path}</string>
|
95
|
+
</array>
|
96
|
+
<key>WatchPaths</key>
|
97
|
+
<array>
|
98
|
+
<string>/Library/Preferences/SystemConfiguration</string>
|
99
|
+
</array>
|
100
|
+
<!-- We specify PATH here because /usr/local/bin, where grownotify -->
|
101
|
+
<!-- is usually installed, is not in the script path by default. -->
|
102
|
+
<key>EnvironmentVariables</key>
|
103
|
+
<dict>
|
104
|
+
<key>PATH</key><string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/bin</string>
|
105
|
+
</dict>
|
106
|
+
</dict>
|
107
|
+
</plist>
|
108
|
+
PLIST
|
109
|
+
File.open(PLIST_FILE, "w") {|f| f << plist }
|
110
|
+
end
|
111
|
+
|
112
|
+
# Register the task with launchd.
|
113
|
+
def register_launchd_task
|
114
|
+
say "Registering #{PLIST_FILE}"
|
115
|
+
system "launchctl load #{PLIST_FILE}"
|
116
|
+
end
|
117
|
+
|
118
|
+
def announce_done
|
119
|
+
controller.run # Choose the right network and get things going
|
120
|
+
say("Sheepsafe installation done!")
|
121
|
+
end
|
122
|
+
|
123
|
+
def uninstall
|
124
|
+
if controller.proxy_running?
|
125
|
+
say "Shutting down SOCKS proxy..."
|
126
|
+
controller.bring_socks_proxy 'down'
|
127
|
+
end
|
128
|
+
if File.exist?(PLIST_FILE)
|
129
|
+
say "Uninstalling Sheepsafe from launchd..."
|
130
|
+
system "launchctl unload #{PLIST_FILE}"
|
131
|
+
File.unlink PLIST_FILE rescue nil
|
132
|
+
end
|
133
|
+
Dir['~/.sheepsafe.*'].each {|f| File.unlink f rescue nil}
|
134
|
+
say "Uninstall finished."
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
def update_config_with_status
|
139
|
+
unless config.trusted_location
|
140
|
+
config.trusted_location = status.current_location
|
141
|
+
end
|
142
|
+
@names = [status.current_network.current_ssid, status.current_network.current_bssid]
|
143
|
+
end
|
144
|
+
|
145
|
+
def sheepsafe_bin_path
|
146
|
+
begin
|
147
|
+
Gem.bin_path('sheepsafe')
|
148
|
+
rescue Exception
|
149
|
+
File.expand_path('../../../bin/sheepsafe', __FILE__)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Sheepsafe
|
2
|
+
class Network
|
3
|
+
def initialize(config = nil)
|
4
|
+
@data = YAML.load(`/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -I`.gsub(/^\s*([^:]+)/, '"\1"'))
|
5
|
+
@config = config || Sheepsafe::Config.new({})
|
6
|
+
end
|
7
|
+
|
8
|
+
def trusted?
|
9
|
+
@config.trusted_names.include?(current_ssid) ||
|
10
|
+
@config.trusted_names.include?(current_bssid)
|
11
|
+
end
|
12
|
+
|
13
|
+
def up?
|
14
|
+
@data['AirPort'] != false
|
15
|
+
end
|
16
|
+
|
17
|
+
def current_ssid
|
18
|
+
@data['SSID']
|
19
|
+
end
|
20
|
+
|
21
|
+
def current_bssid
|
22
|
+
@data['BSSID']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Sheepsafe
|
2
|
+
class Status
|
3
|
+
attr_reader :current_location, :current_network
|
4
|
+
|
5
|
+
def initialize(config = nil)
|
6
|
+
@current_location = `networksetup -getcurrentlocation`.chomp
|
7
|
+
@current_network = Network.new config
|
8
|
+
end
|
9
|
+
|
10
|
+
def network_up?
|
11
|
+
@current_network.up?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/sheepsafe.gemspec
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# -*- encoding: utf-8 ; mode: ruby -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'sheepsafe'
|
5
|
+
s.version = '0.1.0'
|
6
|
+
s.date = '2010-10-26'
|
7
|
+
|
8
|
+
s.rubyforge_project = %q{caldersphere}
|
9
|
+
|
10
|
+
s.summary = "Makes sure you're safe from FireSheep!"
|
11
|
+
s.description = "Automatically toggle network locations and start a SOCKS proxy on untrusted networks. Mac OS X only."
|
12
|
+
|
13
|
+
s.authors = ["Nick Sieger"]
|
14
|
+
s.email = 'nick@nicksieger.com'
|
15
|
+
s.homepage = 'http://github.com/nicksieger/sheepsafe'
|
16
|
+
s.require_paths = %w[lib]
|
17
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
18
|
+
s.extra_rdoc_files = %w[README.md LICENSE]
|
19
|
+
s.executables = ["sheepsafe"]
|
20
|
+
s.default_executable = "sheepsafe"
|
21
|
+
|
22
|
+
s.post_install_message = %[
|
23
|
+
===========================================================================
|
24
|
+
Welcome to Sheepsafe!
|
25
|
+
|
26
|
+
=8P <=== (That\'s a sheep emoji.)
|
27
|
+
|
28
|
+
If this is your first time using Sheepsafe, you probably want to set it up.
|
29
|
+
|
30
|
+
To do that, run \`sheepsafe install\' now.
|
31
|
+
===========================================================================
|
32
|
+
]
|
33
|
+
|
34
|
+
# = MANIFEST =
|
35
|
+
s.files = %w[
|
36
|
+
History.txt
|
37
|
+
LICENSE
|
38
|
+
README.md
|
39
|
+
Rakefile
|
40
|
+
bin/sheepsafe
|
41
|
+
doc/add-untrusted-apply.jpg
|
42
|
+
doc/edit-locations.jpg
|
43
|
+
lib/sheepsafe.rb
|
44
|
+
lib/sheepsafe/config.rb
|
45
|
+
lib/sheepsafe/controller.rb
|
46
|
+
lib/sheepsafe/installer.rb
|
47
|
+
lib/sheepsafe/network.rb
|
48
|
+
lib/sheepsafe/status.rb
|
49
|
+
sheepsafe.gemspec
|
50
|
+
spec/sheepsafe_spec.rb
|
51
|
+
]
|
52
|
+
# = MANIFEST =
|
53
|
+
|
54
|
+
s.test_files = s.files.select { |path| path =~ /^spec\/.*spec.*\.rb/ }
|
55
|
+
|
56
|
+
s.add_dependency(%q<growl>, ["~> 1.0"])
|
57
|
+
s.add_dependency(%q<highline>, ["~> 1.6"])
|
58
|
+
s.add_dependency(%q<daemons>, ["~> 1.1"])
|
59
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.0"])
|
60
|
+
|
61
|
+
s.rubygems_version = %q{1.3.7}
|
62
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
63
|
+
if s.respond_to? :specification_version then
|
64
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
65
|
+
s.specification_version = 3
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'sheepsafe'
|
3
|
+
|
4
|
+
describe Sheepsafe::Controller do
|
5
|
+
let(:config) do
|
6
|
+
mock("config", :trusted_location => "trusted_location", :untrusted_location => "untrusted_location",
|
7
|
+
:last_network= => nil, :write => nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
let (:status) do
|
11
|
+
mock("status", :current_network => "current_network", :network_up? => true)
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:controller) do
|
15
|
+
# Stub out logging
|
16
|
+
Sheepsafe::Controller.new(config, status, mock("logger", :info => nil)).tap do |c|
|
17
|
+
c.stub!(:notify_ok)
|
18
|
+
c.stub!(:notify_warning)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "#network_changed?" do
|
23
|
+
it "is when the current_network is different than the last_network" do
|
24
|
+
config.should_receive(:last_network).and_return "last_network"
|
25
|
+
status.should_receive(:current_network).and_return "current_network"
|
26
|
+
controller.network_changed?.should be_true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "#switch_to_trusted?" do
|
31
|
+
it "is when the current network is trusted" do
|
32
|
+
status.stub_chain(:current_network, :trusted?).and_return true
|
33
|
+
controller.switch_to_trusted?.should be_true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "#switch_to_untrusted?" do
|
38
|
+
it "is when the current network is trusted" do
|
39
|
+
status.stub_chain(:current_network, :trusted?).and_return false
|
40
|
+
controller.switch_to_untrusted?.should be_true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "network didn't change" do
|
45
|
+
before :each do
|
46
|
+
config.should_receive(:last_network).and_return "last_network"
|
47
|
+
status.should_receive(:current_network).and_return "last_network"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "does nothing" do
|
51
|
+
config.should_not_receive(:write)
|
52
|
+
controller.run
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "network is down" do
|
57
|
+
it "does nothing" do
|
58
|
+
status.should_receive(:network_up?).and_return false
|
59
|
+
config.should_not_receive(:write)
|
60
|
+
controller.run
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "network changed" do
|
65
|
+
before :each do
|
66
|
+
controller.stub!(:network_changed?).and_return true
|
67
|
+
controller.stub!(:switch_to_trusted?).and_return false
|
68
|
+
controller.stub!(:switch_to_untrusted?).and_return false
|
69
|
+
end
|
70
|
+
|
71
|
+
it "writes the last network to the configuration" do
|
72
|
+
status.should_receive(:current_network).and_return "current_network"
|
73
|
+
config.should_receive(:last_network=).with("current_network").ordered
|
74
|
+
config.should_receive(:write).ordered
|
75
|
+
controller.run
|
76
|
+
end
|
77
|
+
|
78
|
+
context "to trusted" do
|
79
|
+
it "changes to the trusted location" do
|
80
|
+
controller.should_receive(:switch_to_trusted?).and_return true
|
81
|
+
controller.should_receive(:system).with("scselect trusted_location")
|
82
|
+
controller.should_receive(:bring_socks_proxy).with('down')
|
83
|
+
controller.run
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "to untrusted" do
|
88
|
+
it "changes to the untrusted location" do
|
89
|
+
controller.should_receive(:switch_to_untrusted?).and_return true
|
90
|
+
controller.should_receive(:system).with("scselect untrusted_location")
|
91
|
+
controller.should_receive(:bring_socks_proxy).with('up')
|
92
|
+
controller.run
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe Sheepsafe::Status do
|
99
|
+
let(:status) { Sheepsafe::Status.new }
|
100
|
+
|
101
|
+
its(:current_location) { should_not be_nil }
|
102
|
+
its(:current_network) { should_not be_nil }
|
103
|
+
end
|
104
|
+
|
105
|
+
describe Sheepsafe::Network do
|
106
|
+
let(:current_network) { Sheepsafe::Network.new }
|
107
|
+
|
108
|
+
context "with trusted SSID" do
|
109
|
+
let(:config) { Sheepsafe::Config.new({"trusted_names" => [current_network.current_ssid]}) }
|
110
|
+
subject { Sheepsafe::Network.new(config) }
|
111
|
+
|
112
|
+
it { should be_trusted }
|
113
|
+
end
|
114
|
+
|
115
|
+
context "with trusted BSSID" do
|
116
|
+
let(:config) { Sheepsafe::Config.new({"trusted_names" => [current_network.current_bssid]}) }
|
117
|
+
subject { Sheepsafe::Network.new(config) }
|
118
|
+
|
119
|
+
it { should be_trusted }
|
120
|
+
end
|
121
|
+
|
122
|
+
context "with no trusted names" do
|
123
|
+
subject { Sheepsafe::Network.new }
|
124
|
+
|
125
|
+
it { should_not be_trusted }
|
126
|
+
end
|
127
|
+
end
|
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sheepsafe
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Nick Sieger
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-26 00:00:00 -05:00
|
19
|
+
default_executable: sheepsafe
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: growl
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 15
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 0
|
33
|
+
version: "1.0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: highline
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 3
|
45
|
+
segments:
|
46
|
+
- 1
|
47
|
+
- 6
|
48
|
+
version: "1.6"
|
49
|
+
type: :runtime
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: daemons
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 13
|
60
|
+
segments:
|
61
|
+
- 1
|
62
|
+
- 1
|
63
|
+
version: "1.1"
|
64
|
+
type: :runtime
|
65
|
+
version_requirements: *id003
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: rspec
|
68
|
+
prerelease: false
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ~>
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
hash: 3
|
75
|
+
segments:
|
76
|
+
- 2
|
77
|
+
- 0
|
78
|
+
version: "2.0"
|
79
|
+
type: :development
|
80
|
+
version_requirements: *id004
|
81
|
+
description: Automatically toggle network locations and start a SOCKS proxy on untrusted networks. Mac OS X only.
|
82
|
+
email: nick@nicksieger.com
|
83
|
+
executables:
|
84
|
+
- sheepsafe
|
85
|
+
extensions: []
|
86
|
+
|
87
|
+
extra_rdoc_files:
|
88
|
+
- README.md
|
89
|
+
- LICENSE
|
90
|
+
files:
|
91
|
+
- History.txt
|
92
|
+
- LICENSE
|
93
|
+
- README.md
|
94
|
+
- Rakefile
|
95
|
+
- bin/sheepsafe
|
96
|
+
- doc/add-untrusted-apply.jpg
|
97
|
+
- doc/edit-locations.jpg
|
98
|
+
- lib/sheepsafe.rb
|
99
|
+
- lib/sheepsafe/config.rb
|
100
|
+
- lib/sheepsafe/controller.rb
|
101
|
+
- lib/sheepsafe/installer.rb
|
102
|
+
- lib/sheepsafe/network.rb
|
103
|
+
- lib/sheepsafe/status.rb
|
104
|
+
- sheepsafe.gemspec
|
105
|
+
- spec/sheepsafe_spec.rb
|
106
|
+
has_rdoc: true
|
107
|
+
homepage: http://github.com/nicksieger/sheepsafe
|
108
|
+
licenses: []
|
109
|
+
|
110
|
+
post_install_message: "\n\
|
111
|
+
===========================================================================\n\
|
112
|
+
Welcome to Sheepsafe!\n\n\
|
113
|
+
=8P <=== (That's a sheep emoji.)\n\n\
|
114
|
+
If this is your first time using Sheepsafe, you probably want to set it up.\n\n\
|
115
|
+
To do that, run `sheepsafe install' now.\n\
|
116
|
+
===========================================================================\n "
|
117
|
+
rdoc_options:
|
118
|
+
- --charset=UTF-8
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
hash: 3
|
127
|
+
segments:
|
128
|
+
- 0
|
129
|
+
version: "0"
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ">"
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
hash: 25
|
136
|
+
segments:
|
137
|
+
- 1
|
138
|
+
- 3
|
139
|
+
- 1
|
140
|
+
version: 1.3.1
|
141
|
+
requirements: []
|
142
|
+
|
143
|
+
rubyforge_project: caldersphere
|
144
|
+
rubygems_version: 1.3.7
|
145
|
+
signing_key:
|
146
|
+
specification_version: 3
|
147
|
+
summary: Makes sure you're safe from FireSheep!
|
148
|
+
test_files:
|
149
|
+
- spec/sheepsafe_spec.rb
|