ptj 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.
@@ -0,0 +1,26 @@
1
+ module PTJ
2
+ module Parser
3
+ # FileParser class which allows you to parse a file line by line.
4
+ #
5
+ class PassThreeColons < FileParser
6
+
7
+ # Expecting the following format:
8
+ # something ::: pass ::: something
9
+ # something ::: pass ::: something
10
+ # something ::: pass ::: something
11
+ #
12
+ # @param line
13
+ # Individual line from a text file
14
+ #
15
+ # @return Hash Password, Password Hash
16
+ def parse_line(line)
17
+ if line =~ /\s*\S*\s*:::\s*(\S+)\s*:::/
18
+ pass = $~[1]
19
+ hash = nil
20
+ end
21
+ {:mypass => pass, :myhash => hash}
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,120 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ptj}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Josh Grunzweig"]
12
+ s.date = %q{2011-08-29}
13
+ s.description = %q{An easy way to collect and analyze data about password
14
+ databases.}
15
+ s.email = %q{jgrunzweig@gmail.com}
16
+ s.extra_rdoc_files = [
17
+ "LICENSE.txt",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "etc/config.yml",
29
+ "lib/ptj.rb",
30
+ "lib/ptj/default_setup.rb",
31
+ "lib/ptj/environment.rb",
32
+ "lib/ptj/ext.rb",
33
+ "lib/ptj/ext/datamapper_collection.rb",
34
+ "lib/ptj/model.rb",
35
+ "lib/ptj/model/password.rb",
36
+ "lib/ptj/model/tag.rb",
37
+ "lib/ptj/model/tasks.rb",
38
+ "lib/ptj/parser.rb",
39
+ "lib/ptj/parser/fileparser.rb",
40
+ "lib/ptj/parser/fileparser/countpassonly.rb",
41
+ "lib/ptj/parser/fileparser/hashpassonlycolon.rb",
42
+ "lib/ptj/parser/fileparser/passhashonly.rb",
43
+ "lib/ptj/parser/fileparser/passonly.rb",
44
+ "lib/ptj/parser/fileparser/passthreecolons.rb",
45
+ "ptj.gemspec",
46
+ "scripts/analyze.rb",
47
+ "scripts/generate_wordlist.rb",
48
+ "scripts/import.rb",
49
+ "scripts/ptj_libpath.rb",
50
+ "spec/.helper.rb.swp",
51
+ "spec/.test_ptj.rb.swp",
52
+ "spec/model/password_spec.rb",
53
+ "spec/model/shared_behaviors.rb",
54
+ "spec/model/tag_spec.rb",
55
+ "spec/spec_helper.rb",
56
+ "spec/spec_ptj.rb",
57
+ "tasks/db.rake",
58
+ "tasks/irb.rake"
59
+ ]
60
+ s.homepage = %q{http://github.com/jgrunzweig/ptj}
61
+ s.licenses = ["MIT"]
62
+ s.require_paths = ["lib"]
63
+ s.rubygems_version = %q{1.6.2}
64
+ s.summary = %q{Password analysis and collection database.}
65
+
66
+ if s.respond_to? :specification_version then
67
+ s.specification_version = 3
68
+
69
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
70
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
71
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
72
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
73
+ s.add_development_dependency(%q<rcov>, [">= 0"])
74
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
75
+ s.add_development_dependency(%q<dm-core>, [">= 0"])
76
+ s.add_development_dependency(%q<dm-migrations>, [">= 0"])
77
+ s.add_development_dependency(%q<dm-types>, [">= 0"])
78
+ s.add_development_dependency(%q<dm-transactions>, [">= 0"])
79
+ s.add_development_dependency(%q<dm-aggregates>, [">= 0"])
80
+ s.add_development_dependency(%q<dm-validations>, [">= 0"])
81
+ s.add_development_dependency(%q<dm-serializer>, [">= 0"])
82
+ s.add_development_dependency(%q<dm-timestamps>, [">= 0"])
83
+ s.add_development_dependency(%q<dm-sqlite-adapter>, [">= 0"])
84
+ s.add_development_dependency(%q<dm-postgres-adapter>, [">= 0"])
85
+ else
86
+ s.add_dependency(%q<shoulda>, [">= 0"])
87
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
88
+ s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
89
+ s.add_dependency(%q<rcov>, [">= 0"])
90
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
91
+ s.add_dependency(%q<dm-core>, [">= 0"])
92
+ s.add_dependency(%q<dm-migrations>, [">= 0"])
93
+ s.add_dependency(%q<dm-types>, [">= 0"])
94
+ s.add_dependency(%q<dm-transactions>, [">= 0"])
95
+ s.add_dependency(%q<dm-aggregates>, [">= 0"])
96
+ s.add_dependency(%q<dm-validations>, [">= 0"])
97
+ s.add_dependency(%q<dm-serializer>, [">= 0"])
98
+ s.add_dependency(%q<dm-timestamps>, [">= 0"])
99
+ s.add_dependency(%q<dm-sqlite-adapter>, [">= 0"])
100
+ s.add_dependency(%q<dm-postgres-adapter>, [">= 0"])
101
+ end
102
+ else
103
+ s.add_dependency(%q<shoulda>, [">= 0"])
104
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
105
+ s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
106
+ s.add_dependency(%q<rcov>, [">= 0"])
107
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
108
+ s.add_dependency(%q<dm-core>, [">= 0"])
109
+ s.add_dependency(%q<dm-migrations>, [">= 0"])
110
+ s.add_dependency(%q<dm-types>, [">= 0"])
111
+ s.add_dependency(%q<dm-transactions>, [">= 0"])
112
+ s.add_dependency(%q<dm-aggregates>, [">= 0"])
113
+ s.add_dependency(%q<dm-validations>, [">= 0"])
114
+ s.add_dependency(%q<dm-serializer>, [">= 0"])
115
+ s.add_dependency(%q<dm-timestamps>, [">= 0"])
116
+ s.add_dependency(%q<dm-sqlite-adapter>, [">= 0"])
117
+ s.add_dependency(%q<dm-postgres-adapter>, [">= 0"])
118
+ end
119
+ end
120
+
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pp'
3
+ require 'optparse'
4
+
5
+ require_relative('ptj_libpath')
6
+ require 'ptj/default_setup'
7
+
8
+ DataMapper::Model.raise_on_save_failure = true if $DEBUG
9
+
10
+ include PTJ
11
+
12
+ #FILTER = {:fields => [:id, :password, :upper, :lower, :special, :number, :size]}
13
+ FILTER = {}
14
+ CFG = {
15
+ :tags => [],
16
+ :file => nil,
17
+ :includecount => false
18
+ }
19
+
20
+ opts = OptionParser.new do |o|
21
+ o.banner = "Usage: #{File.basename $0} [opts]"
22
+
23
+ o.on_tail("-h", "--help", "Show this message") do
24
+ puts o
25
+ exit 1
26
+ end
27
+
28
+ o.on("-t", "--tags TAGS", "Tags to be used to when querying passwords (separated by a comma)") do |t|
29
+ t = t.split(",").each{|x| x.strip!}
30
+ t=[t] unless t.is_a?(Array)
31
+ t.each do |tag|
32
+ CFG[:tags] << tag
33
+ end
34
+ end
35
+
36
+ o.on("--max-size SIZE", Integer, "Maximum size of the resulting passords") do |f|
37
+ FILTER[:size.lt] = f
38
+ end
39
+
40
+ o.on("--min-size SIZE", Integer, "Minimum size of the resulting passwords") do |f|
41
+ FILTER[:size.gt] = f
42
+ end
43
+
44
+ o.on("--[no-]upper", "Query based on upper-case letters") do |f|
45
+ FILTER[:upper] = f
46
+ end
47
+
48
+ o.on("--[no-]lower", "Query based on lower-case letters") do |f|
49
+ FILTER[:lower] = f
50
+ end
51
+
52
+ o.on("--[no-]special", "Query based on special charaters") do |f|
53
+ FILTER[:special] = f
54
+ end
55
+
56
+ o.on("--[no-]number", "Query based on numbers") do |f|
57
+ FILTER[:number] = f
58
+ end
59
+
60
+ end.parse!(ARGV)
61
+
62
+ def top5_pass(object, my_hash)
63
+ my_hash.delete(:fields) if my_hash[:fields]
64
+ my_hash.delete(:order) if my_hash[:order]
65
+ return object.aggregate(:password, :password.count, my_hash).sort {|x,y| y[1] <=> x[1]}.first(5)
66
+ end
67
+
68
+ def size_count(object, my_hash)
69
+ my_hash.delete(:fields) if my_hash[:fields]
70
+ my_hash.delete(:order) if my_hash[:order]
71
+ return object.aggregate(:size, :size.count, my_hash).sort {|x,y| x[0] <=> y[0]}
72
+ end
73
+
74
+ def cat_result(object, my_hash)
75
+ my_hash.delete(:fields) if my_hash[:fields]
76
+ my_hash.delete(:order) if my_hash[:order]
77
+ return_hash = {}
78
+ return_hash["Lower"] = object.all(my_hash).count(:upper => false, :special => false, :lower => true, :number => false)
79
+ return_hash["Upper"] = object.all(my_hash).count(:upper => true, :special => false, :lower => false, :number => false)
80
+ return_hash["Number"] = object.all(my_hash).count(:upper => false, :special => false, :lower => false, :number => true)
81
+ return_hash["Special"] = object.all(my_hash).count(:upper => false, :special => true, :lower => false, :number => false)
82
+ return_hash["Lower/Upper"] = object.all(my_hash).count(:upper => true, :special => false, :lower => true, :number => false)
83
+ return_hash["Lower/Number"] = object.all(my_hash).count(:upper => false, :special => false, :lower => true, :number => true)
84
+ return_hash["Upper/Number"] = object.all(my_hash).count(:upper => true, :special => false, :lower => false, :number => true)
85
+ return_hash["Lower/Special"] = object.all(my_hash).count(:upper => false, :special => true, :lower => true, :number => false)
86
+ return_hash["Upper/Special"] = object.all(my_hash).count(:upper => true, :special => true, :lower => false, :number => false)
87
+ return_hash["Number/Special"] = object.all(my_hash).count(:upper => false, :special => true, :lower => false, :number =>true)
88
+ return_hash["Lower/Upper/Number"] = object.all(my_hash).count(:upper => true, :special => false, :lower => true, :number => true)
89
+ return_hash["Lower/Upper/Special"] = object.all(my_hash).count(:upper => true, :special => true, :lower => true, :number => false)
90
+ return_hash["Lower/Number/Special"] = object.all(my_hash).count(:upper => false, :special => true, :lower => true, :number => true)
91
+ return_hash["Upper/Number/Special"] = object.all(my_hash).count(:upper => true, :special => true, :lower => false, :number =>true)
92
+ return_hash["Lower/Upper/Number/Special"] = object.all(my_hash).count(:upper => true, :special => true, :lower => true, :number => true)
93
+ return_hash
94
+ end
95
+
96
+ time_now = Time.now
97
+ if CFG[:tags]
98
+ top5 = top5_pass(PTJ::Tag.all(:tag => CFG[:tags]).passwords, FILTER)
99
+ my_count = size_count(PTJ::Tag.all(:tag => CFG[:tags]).passwords, FILTER)
100
+ split_up = cat_result(PTJ::Tag.all(:tag => CFG[:tags]).passwords, FILTER)
101
+ else
102
+ top5 = top5_pass(PTJ::Passwords.all, FILTER)
103
+ my_count = size_count(PTJ::Passwords.all, FILTER)
104
+ split_up = cat_result(PTJ::Passwords.all, FILTER)
105
+ end
106
+
107
+
108
+ puts "-=-=-=-=-=- Top 5 Passwords -=-=-=-=-=-"
109
+ top5.each do |pass, count|
110
+ printf("%-30s : %d", pass, count)
111
+ puts ""
112
+ end
113
+
114
+ total_size = 0
115
+ my_count.each{|result| total_size += result[1] }
116
+ puts "\n-=-=-=-=-=- Password Length -=-=-=-=-=-"
117
+ my_count.each do |result|
118
+ percent = "%.2f" % ((result[1].to_f/total_size.to_f)*100).to_f
119
+ printf("%-30s %s", ("Password Length: #{result[0]}"), ("Count: #{result[1]} (#{percent}%)") )
120
+ puts ""
121
+ end
122
+ puts "Total: #{total_size}"
123
+
124
+ puts "\n-=-=-=-=-=- Password Type -=-=-=-=-=-"
125
+ split_up.sort_by{|k,v| k.length}.each do |result|
126
+ printf("Type: %-30s %s", result[0], ("Result: #{result[1]}"))
127
+ puts ""
128
+ end
129
+ p "Time taken: #{Time.now - time_now}"
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pp'
3
+ require 'optparse'
4
+
5
+ require_relative('ptj_libpath')
6
+ require 'ptj/default_setup'
7
+
8
+ DataMapper::Model.raise_on_save_failure = true if $DEBUG
9
+
10
+ include PTJ
11
+
12
+ FILTER = {:fields => [:password, :id]}
13
+
14
+ CFG = {
15
+ :tags => [],
16
+ :file => nil,
17
+ :includecount => false
18
+ }
19
+
20
+ opts = OptionParser.new do |o|
21
+ o.banner = "Usage: #{File.basename $0} [opts]"
22
+
23
+ o.on_tail("-h", "--help", "Show this message") do
24
+ puts o
25
+ exit 1
26
+ end
27
+
28
+ o.on("-t", "--tags TAGS", "Tags to be used to when querying passwords (separated by a comma)") do |t|
29
+ t = t.split(",").each{|x| x.strip!}
30
+ t=[t] unless t.is_a?(Array)
31
+ t.each do |tag|
32
+ CFG[:tags] << tag
33
+ end
34
+ end
35
+
36
+ o.on("-o", "--output FILENAME", String, "Where to output results (Default outputs to screen)") do |f|
37
+ CFG[:file] = f
38
+ end
39
+
40
+ o.on("--max-size SIZE", Integer, "Maximum size of the resulting passords") do |f|
41
+ FILTER[:size.lt] = f
42
+ end
43
+
44
+ o.on("--min-size SIZE", Integer, "Minimum size of the resulting passwords") do |f|
45
+ FILTER[:size.gt] = f
46
+ end
47
+
48
+ o.on("--max-results SIZE", Integer, "Maximum number of results to return") do |f|
49
+ CFG[:max_results] = f
50
+ end
51
+
52
+ o.on("--include-count", "Include the counts of passwords identified") do |f|
53
+ CFG[:includecount] = f
54
+ end
55
+
56
+ o.on("--[no-]upper", "Query based on upper-case letters") do |f|
57
+ FILTER[:upper] = f
58
+ end
59
+
60
+ o.on("--[no-]lower", "Query based on lower-case letters") do |f|
61
+ FILTER[:lower] = f
62
+ end
63
+
64
+ o.on("--[no-]special", "Query based on special charaters") do |f|
65
+ FILTER[:special] = f
66
+ end
67
+
68
+ o.on("--[no-]number", "Query based on numbers") do |f|
69
+ FILTER[:number] = f
70
+ end
71
+
72
+
73
+ end.parse!(ARGV)
74
+
75
+ time_now = Time.now
76
+
77
+ #raise(OptionParser::MissingArgument, "Must specify file with -f or password with -p") if (CFG[:file].nil? and CFG[:password].nil?)
78
+ def top_pass(object, my_hash)
79
+ my_hash.delete(:fields) if my_hash[:fields]
80
+ my_hash.delete(:order) if my_hash[:order]
81
+ return object.aggregate(:password, :password.count, my_hash).sort {|x,y| y[1] <=> x[1]}
82
+ end
83
+
84
+ if CFG[:tags]
85
+ if CFG[:max_results]
86
+ o_pass = top_pass(PTJ::Tag.all(:tag => CFG[:tags]).passwords, FILTER).first(CFG[:max_results])
87
+ else
88
+ o_pass = top_pass(PTJ::Tag.all(:tag => CFG[:tags]).passwords, FILTER)
89
+ end
90
+ else
91
+ if CFG[:max_results]
92
+ o_pass = top_pass(PTJ::Passwords.all, FILTER).first(CFG[:max_results])
93
+ else
94
+ o_pass = top_pass(PTJ::Passwords.all, FILTER)
95
+ end
96
+ end
97
+
98
+
99
+ if CFG[:file]
100
+ File.open(CFG[:file], "w+") do |file_handle|
101
+ o_pass.each do |tiny_array|
102
+ if CFG[:includecount]
103
+ file_handle.puts "#{tiny_array[0]}, #{tiny_array[1]}"
104
+ else
105
+ file_handle.puts "#{tiny_array[0]}"
106
+ end
107
+ end
108
+ end
109
+ else
110
+ o_pass.each do |tiny_array|
111
+ if CFG[:includecount]
112
+ puts "#{tiny_array[0]}, #{tiny_array[1]}"
113
+ else
114
+ puts "#{tiny_array[0]}"
115
+ end
116
+ end
117
+ end
118
+ puts "Time Taken: #{Time.now - time_now}"
119
+ exit
120
+
121
+
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pp'
3
+ require 'optparse'
4
+
5
+ require_relative('ptj_libpath')
6
+ require 'ptj/default_setup'
7
+
8
+ DataMapper::Model.raise_on_save_failure = true if $DEBUG
9
+
10
+ include PTJ
11
+
12
+ FILTER = {}
13
+
14
+ CFG = {
15
+ :password => nil,
16
+ :pw_hash => "",
17
+ :tags => [],
18
+ :basename => true,
19
+ :file => nil
20
+ }
21
+
22
+ opts = OptionParser.new do |o|
23
+ o.banner = "Usage: #{File.basename $0} [opts] -f file|-p password"
24
+
25
+ o.on_tail("-h", "--help", "Show this message.") do
26
+ puts o
27
+ exit 1
28
+ end
29
+
30
+ o.on("-t", "--tag TAGS", "Tags to be used to identify imported passwords (separated by a comma)") do |t|
31
+ t = t.split(",").each{|x| x.strip!}
32
+ t=[t] unless t.is_a?(Array)
33
+ t.each do |tag|
34
+ mytag=(Tag.get(tag) || Tag.create(:tag => tag.to_s))
35
+ CFG[:tags] << mytag
36
+ end
37
+ end
38
+
39
+ o.on("--[no-]strict", "Enable/Disable Strict Mode") do |s|
40
+ DataMapper::Model.raise_on_save_failure = s
41
+ end
42
+
43
+ o.on("-f", "--file FILENAME", String, "File to import.") do |f|
44
+ CFG[:file] = f
45
+ end
46
+
47
+ o.on("-r", "--parser NUMBER", Integer, "File parser to use:", "1 - Password Only", "2 - Hash:Password", "3 - Count, Password", "4 - Something ::: Password ::: Something") do |f|
48
+ case f
49
+ when 1
50
+ CFG[:parser] = Parser::PassOnly.new
51
+ when 2
52
+ CFG[:parser] = Parser::HashPassOnlyColon.new
53
+ when 3
54
+ CFG[:parser] = Parser::CountPassOnly.new
55
+ when 4
56
+ CFG[:parser] = Parser::PassThreeColons.new
57
+ else
58
+ raise(OptionParser::InvalidOption, "Incorrect parsing number specified.")
59
+ end
60
+ end
61
+
62
+ o.on("-p", "--password PASSWORD", String, "Password to import.") do |f|
63
+ CFG[:file] = f
64
+ end
65
+
66
+ o.on("-a", "--hash HASH", String, "Hash to import (Use in conjunction with -p).") do |f|
67
+ CFG[:file] = f
68
+ end
69
+
70
+ end.parse!(ARGV)
71
+
72
+ raise(OptionParser::MissingArgument, "Must specify file with -f or password with -p") if (CFG[:file].nil? and CFG[:password].nil?)
73
+
74
+ #o_pass_count = Password.all(:fields => [:id]).size
75
+
76
+
77
+ def import_file
78
+ file = Pathname.new(CFG[:file])
79
+ parser = CFG[:parser]
80
+ tags = CFG[:tags]
81
+ file = File.open(CFG[:file], "r")
82
+ lines = file.readlines
83
+ lines.each do |line|
84
+ begin
85
+ line = line.force_encoding("BINARY")
86
+ parsed = parser.parse_line(line)
87
+ mypass = parsed[:mypass]
88
+ myhash = parsed[:myhash]
89
+ next if mypass.to_s.empty?
90
+ if parsed[:count]
91
+ parsed[:count].to_i.times do
92
+ pass = Password.add_single(mypass, myhash)
93
+ tags.each{|tag| pass.tags << tag}
94
+ pass.save
95
+ #puts "Adding #{mypass}"
96
+ end
97
+ else
98
+ pass = Password.add_single(mypass, myhash)
99
+ tags.each{|tag| pass.tags << tag}
100
+ pass.save
101
+ #puts "Adding #{mypass}"
102
+ end
103
+ rescue
104
+ next
105
+ end
106
+ end
107
+ end
108
+
109
+ import_file
110
+
111
+