to_pass 0.2.4 → 0.4.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/Rakefile +43 -11
- data/TODO +21 -2
- data/VERSION +1 -1
- data/lib/to_pass/algorithm_reader.rb +11 -2
- data/lib/{algorithms → to_pass/algorithms}/basic_de.yml +5 -5
- data/lib/{algorithms → to_pass/algorithms}/basic_en.yml +5 -5
- data/lib/to_pass/cli.rb +12 -4
- data/lib/to_pass/converter.rb +27 -10
- data/lib/to_pass/converter_reader.rb +107 -0
- data/lib/to_pass/converters/collapse_chars.rb +12 -0
- data/lib/to_pass/converters/first_chars.rb +12 -0
- data/lib/to_pass/converters/replace.rb +12 -0
- data/lib/to_pass/converters/swapcase.rb +25 -0
- data/lib/to_pass/converters.rb +14 -0
- data/lib/to_pass.rb +2 -1
- data/test/fixtures/user_alg.yml +5 -5
- data/test/fixtures/user_converter.rb +17 -0
- data/test/helper.rb +7 -1
- data/test/test_algorithm_reader.rb +6 -1
- data/test/test_cli.rb +12 -0
- data/test/test_converter.rb +38 -9
- data/test/test_converter_reader.rb +64 -0
- data/test/test_converters.rb +10 -0
- metadata +18 -9
- data/lib/to_pass/string_conversions.rb +0 -54
- data/test/test_string_conversions.rb +0 -40
data/Rakefile
CHANGED
@@ -24,20 +24,24 @@ rescue LoadError
|
|
24
24
|
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
27
|
+
# documentation task
|
28
|
+
begin
|
29
|
+
%w[ rake/rdoctask sdoc ].each { |lib| require lib }
|
30
|
+
Rake::RDocTask.new do |rdoc|
|
31
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
32
|
+
|
33
|
+
rdoc.rdoc_dir = 'doc/rdoc'
|
34
|
+
rdoc.title = "to_pass #{version}"
|
35
|
+
rdoc.options << '--fmt' << 'shtml'
|
36
|
+
rdoc.template = 'direct'
|
37
|
+
rdoc.rdoc_files.include('README*')
|
38
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
39
|
+
end
|
40
|
+
rescue LoadError
|
37
41
|
end
|
38
42
|
|
39
43
|
desc "run tests"
|
40
|
-
task :test
|
44
|
+
task :test do
|
41
45
|
# optional libraries
|
42
46
|
%w[ redgreen ].each do |lib|
|
43
47
|
begin
|
@@ -50,4 +54,32 @@ task :test, :needs => [:check_dependencies] do
|
|
50
54
|
end
|
51
55
|
end
|
52
56
|
|
57
|
+
desc "list available algorithms"
|
58
|
+
task :algorithms, :needs => [:to_pass] do
|
59
|
+
puts ""
|
60
|
+
puts " available password algorithms"
|
61
|
+
puts " ============================================"
|
62
|
+
ToPass::AlgorithmReader.discover.each do |algorithm|
|
63
|
+
puts " - #{algorithm}"
|
64
|
+
end
|
65
|
+
puts " ============================================"
|
66
|
+
puts ""
|
67
|
+
end
|
68
|
+
|
69
|
+
desc "list available converters"
|
70
|
+
task :converters, :needs => [:to_pass] do
|
71
|
+
puts ""
|
72
|
+
puts " available converters for password algorithms"
|
73
|
+
puts " ============================================"
|
74
|
+
ToPass::ConverterReader.new.discover.each do |converter|
|
75
|
+
puts " - #{converter}"
|
76
|
+
end
|
77
|
+
puts " ============================================"
|
78
|
+
puts ""
|
79
|
+
end
|
80
|
+
|
81
|
+
task :to_pass do
|
82
|
+
require 'lib/to_pass'
|
83
|
+
end
|
84
|
+
|
53
85
|
task :default => :test
|
data/TODO
CHANGED
@@ -1,9 +1,28 @@
|
|
1
1
|
UP NEXT
|
2
2
|
============================================================================
|
3
|
-
-
|
3
|
+
- make it debian compatible (most of which is common sense anyway)
|
4
|
+
http://pkg-ruby-extras.alioth.debian.org/upstream-devs.html
|
5
|
+
- Distribute your software as a source code archive
|
6
|
+
- Use setup.rb
|
7
|
+
- Remove all references to rubygems in the software you ship
|
8
|
+
- Don’t make your Rakefile depend on RubyGems
|
9
|
+
- Make your tests and examples usable outside of your directory tree
|
10
|
+
- Use a shebang that works everywhere
|
11
|
+
- Provide man pages for your binaries
|
12
|
+
- If possible, maintain a backward-compatible API
|
13
|
+
|
14
|
+
- Man-Pages http://www.linuxhowtos.org/System/creatingman.htm
|
15
|
+
order:
|
16
|
+
NAME
|
17
|
+
SYNOPSIS
|
18
|
+
DESCRIPTION
|
19
|
+
OPTIONS
|
20
|
+
BUGS
|
21
|
+
AUTHOR
|
22
|
+
SEE ALSO
|
23
|
+
|
4
24
|
|
5
25
|
SOMEDAY
|
6
26
|
============================================================================
|
7
27
|
- move decision wether a string is a word or not into algorithm definition.
|
8
|
-
- make conversion-functions more pluggable
|
9
28
|
- test on windows
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
@@ -4,7 +4,7 @@
|
|
4
4
|
require 'pathname'
|
5
5
|
require 'yaml'
|
6
6
|
|
7
|
-
# The AlgorithmReader's primary API is
|
7
|
+
# The AlgorithmReader's primary API is to load the rules from a YAML-file
|
8
8
|
# into a Hash.
|
9
9
|
#
|
10
10
|
# Algorithms are searched in the following locations
|
@@ -20,7 +20,7 @@ class ToPass::AlgorithmReader
|
|
20
20
|
@load_path = []
|
21
21
|
[
|
22
22
|
'~/.to_pass/algorithms',
|
23
|
-
"#{File.dirname(__FILE__)}
|
23
|
+
"#{File.dirname(__FILE__)}/algorithms"
|
24
24
|
].each do |dir|
|
25
25
|
dir = Pathname.new(dir).expand_path
|
26
26
|
@load_path << dir if dir.exist?
|
@@ -32,6 +32,15 @@ class ToPass::AlgorithmReader
|
|
32
32
|
def load(algorithm)
|
33
33
|
new(algorithm).load_from_file
|
34
34
|
end
|
35
|
+
|
36
|
+
# searches for available algorithms
|
37
|
+
def discover
|
38
|
+
new(nil).load_path.collect do |dir|
|
39
|
+
Dir["#{dir}/*.yml"]
|
40
|
+
end.flatten.compact.map do |fn|
|
41
|
+
File.basename(fn).gsub('.yml', '')
|
42
|
+
end
|
43
|
+
end
|
35
44
|
end
|
36
45
|
|
37
46
|
def load_from_file # :nodoc:
|
@@ -1,14 +1,14 @@
|
|
1
1
|
desc: Basic Algorithm with a german usage in mind
|
2
2
|
name: Basic (german)
|
3
3
|
sentence:
|
4
|
-
-
|
4
|
+
- replace: words
|
5
5
|
- first_chars
|
6
|
-
-
|
6
|
+
- replace: symbols
|
7
7
|
- collapse_chars
|
8
8
|
word:
|
9
|
-
-
|
10
|
-
-
|
11
|
-
|
9
|
+
- replace: chars
|
10
|
+
- replace: symbols
|
11
|
+
replacements:
|
12
12
|
words:
|
13
13
|
ein: 1
|
14
14
|
eine: 1
|
@@ -1,14 +1,14 @@
|
|
1
1
|
desc: Basic Algorithm with a english usage in mind
|
2
2
|
name: Basic (english)
|
3
3
|
sentence:
|
4
|
-
-
|
4
|
+
- replace: words
|
5
5
|
- first_chars
|
6
|
-
-
|
6
|
+
- replace: symbols
|
7
7
|
- collapse_chars
|
8
8
|
word:
|
9
|
-
-
|
10
|
-
-
|
11
|
-
|
9
|
+
- replace: chars
|
10
|
+
- replace: symbols
|
11
|
+
replacements:
|
12
12
|
words:
|
13
13
|
one: 1
|
14
14
|
single: 1
|
data/lib/to_pass/cli.rb
CHANGED
@@ -12,7 +12,7 @@ module ToPass
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def output
|
15
|
-
if @options[:
|
15
|
+
if @options[:pipe_out]
|
16
16
|
$stdout << @password
|
17
17
|
else
|
18
18
|
puts @password
|
@@ -24,7 +24,9 @@ module ToPass
|
|
24
24
|
# parse the options
|
25
25
|
def parse_options
|
26
26
|
options = {
|
27
|
-
:algorithm
|
27
|
+
:algorithm => 'basic_de',
|
28
|
+
:pipe_out => false,
|
29
|
+
:pipe_in => false
|
28
30
|
}
|
29
31
|
|
30
32
|
OptionParser.new do |opts|
|
@@ -35,6 +37,10 @@ module ToPass
|
|
35
37
|
options[:algorithm] = value
|
36
38
|
end
|
37
39
|
|
40
|
+
opts.on('-p', '--[no-]pipe', "pipe result to stdout (without trailing linebreak)") do |value|
|
41
|
+
options[:pipe_out] = value
|
42
|
+
end
|
43
|
+
|
38
44
|
opts.separator ""
|
39
45
|
|
40
46
|
opts.on_tail("-h", "--help", "Show this message") do
|
@@ -43,14 +49,16 @@ module ToPass
|
|
43
49
|
end
|
44
50
|
end.parse!
|
45
51
|
|
46
|
-
|
52
|
+
if ARGV[0].nil?
|
53
|
+
options[:pipe_in] = options[:pipe_out] = true
|
54
|
+
end
|
47
55
|
|
48
56
|
options
|
49
57
|
end
|
50
58
|
|
51
59
|
# get the input string
|
52
60
|
def get_input_string
|
53
|
-
unless @options[:
|
61
|
+
unless @options[:pipe_in]
|
54
62
|
ARGV[0]
|
55
63
|
else
|
56
64
|
$stdin.read.chomp
|
data/lib/to_pass/converter.rb
CHANGED
@@ -10,9 +10,12 @@ module ToPass
|
|
10
10
|
# a more complete description of the algorithm capabilities
|
11
11
|
# is still pending.
|
12
12
|
class Converter
|
13
|
+
attr_accessor :converters, :rules
|
13
14
|
# create a new converter, based on a set of conversion-rules
|
14
15
|
def initialize( rules )
|
15
16
|
@rules = rules
|
17
|
+
@reader = ConverterReader.new
|
18
|
+
@converters = @reader.discover
|
16
19
|
end
|
17
20
|
|
18
21
|
# convert a string into a password
|
@@ -31,9 +34,16 @@ module ToPass
|
|
31
34
|
# end
|
32
35
|
# end
|
33
36
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
+
# proxy to converters
|
38
|
+
def respond_to?(method_name) # :nodoc:
|
39
|
+
if [:convert, :rules_for, :process].include? method_name.to_sym
|
40
|
+
true
|
41
|
+
elsif @converters.include? method_name.to_sym
|
42
|
+
true
|
43
|
+
else
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
37
47
|
|
38
48
|
private
|
39
49
|
|
@@ -52,13 +62,20 @@ module ToPass
|
|
52
62
|
# process the string, rule by rule
|
53
63
|
def process(string, rules)
|
54
64
|
rules.inject(string) do |pwd, rule|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
65
|
+
apply_rule(pwd, rule)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# apply a single rule to the password-to-be
|
70
|
+
def apply_rule(pwd, rule)
|
71
|
+
cmd, args = rule.to_a.flatten
|
72
|
+
m = @reader.load(cmd.to_sym).method(cmd.to_sym)
|
73
|
+
|
74
|
+
case m.arity
|
75
|
+
when 1
|
76
|
+
m.call(pwd)
|
77
|
+
when 3, -2
|
78
|
+
m.call(pwd, @rules, *args)
|
62
79
|
end
|
63
80
|
end
|
64
81
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# vim:ft=ruby:enc=utf-8
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
# The ConverterReader's primary API is to load the converters from right
|
7
|
+
# directories into an Array
|
8
|
+
#
|
9
|
+
# Converters are searched in the following locations
|
10
|
+
#
|
11
|
+
# 1. ~/.to_pass/converters
|
12
|
+
# 2. bundled converters of gem
|
13
|
+
#
|
14
|
+
# The bundled converter are, however, lazily loaded with autoload.
|
15
|
+
# User-provided converters are always required (for now).
|
16
|
+
#
|
17
|
+
class ToPass::ConverterReader
|
18
|
+
attr_reader :load_path, :loaded
|
19
|
+
|
20
|
+
def initialize # :nodoc:
|
21
|
+
@load_path = []
|
22
|
+
@loaded = []
|
23
|
+
@discovered = []
|
24
|
+
[
|
25
|
+
'~/.to_pass/converters',
|
26
|
+
"#{File.dirname(__FILE__)}/converters"
|
27
|
+
].each do |dir|
|
28
|
+
dir = Pathname.new(dir).expand_path
|
29
|
+
@load_path << dir if dir.exist?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# loads the converters
|
34
|
+
def load(converter)
|
35
|
+
unless @loaded.include?(converter.to_sym)
|
36
|
+
load_from_file(converter)
|
37
|
+
@loaded << converter
|
38
|
+
end
|
39
|
+
|
40
|
+
classname(converter)
|
41
|
+
end
|
42
|
+
|
43
|
+
# discover a list of available converters
|
44
|
+
def discover
|
45
|
+
search_for_converters
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def search_for_converters # :nodoc:
|
51
|
+
files = load_path.collect do |directory|
|
52
|
+
dir = Pathname.new(directory)
|
53
|
+
if dir.exist?
|
54
|
+
Dir["#{dir}/*.rb"].collect do |converter|
|
55
|
+
fn_re = %r!/([^/]*)\.rb$!i
|
56
|
+
name = converter.match(fn_re)
|
57
|
+
if name
|
58
|
+
name[1].to_sym
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end.flatten.compact
|
63
|
+
|
64
|
+
raise LoadError, "converters could not be found in #{load_path}" if files.nil?
|
65
|
+
|
66
|
+
@discovered = files
|
67
|
+
end
|
68
|
+
|
69
|
+
def load_from_file(converter) # :nodoc:
|
70
|
+
fn = load_path.collect do |dir|
|
71
|
+
path = Pathname.new("#{dir}/#{converter}.rb").expand_path
|
72
|
+
|
73
|
+
if path.exist?
|
74
|
+
path
|
75
|
+
else
|
76
|
+
next
|
77
|
+
end
|
78
|
+
end.compact.first
|
79
|
+
|
80
|
+
raise LoadError, "converter '#{converter}' could not be found in #{load_path}" if fn.nil?
|
81
|
+
|
82
|
+
if require fn
|
83
|
+
classname converter
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def classname(converter) # :nodoc:
|
88
|
+
constantize("ToPass::Converters::#{camel_case(converter)}")
|
89
|
+
end
|
90
|
+
|
91
|
+
def constantize(camel_cased_word) # :nodoc:
|
92
|
+
names = camel_cased_word.split('::')
|
93
|
+
names.shift if names.empty? || names.first.empty?
|
94
|
+
|
95
|
+
constant = Object
|
96
|
+
names.each do |name|
|
97
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
98
|
+
end
|
99
|
+
constant
|
100
|
+
end
|
101
|
+
|
102
|
+
def camel_case(underscored_word) # :nodoc:
|
103
|
+
camel_cased_word = underscored_word.to_s.split('_').map do |part|
|
104
|
+
part.capitalize
|
105
|
+
end.join('')
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module ToPass::Converters
|
2
|
+
class Replace
|
3
|
+
class << self
|
4
|
+
# perform replacements on a string, based on a replacment table
|
5
|
+
def replace(string, rules, tablename)
|
6
|
+
rules['replacements'][tablename].inject(string) do |pwd, map|
|
7
|
+
pwd = pwd.gsub(/#{map[0].to_s}/, map[1].to_s)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module ToPass::Converters
|
2
|
+
class Swapcase
|
3
|
+
class << self
|
4
|
+
# alternate case of letter (not numbers)
|
5
|
+
def swapcase(string)
|
6
|
+
pwd = ""
|
7
|
+
last_upcase = true
|
8
|
+
|
9
|
+
string.each_char do |char|
|
10
|
+
char = if char.between?("0", "9")
|
11
|
+
char
|
12
|
+
elsif last_upcase
|
13
|
+
last_upcase = false
|
14
|
+
char.downcase
|
15
|
+
else
|
16
|
+
last_upcase = true
|
17
|
+
char.upcase
|
18
|
+
end
|
19
|
+
pwd << char
|
20
|
+
end
|
21
|
+
pwd
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# vim:ft=ruby:enc=utf-8
|
3
|
+
|
4
|
+
module ToPass
|
5
|
+
# The Converters-class is a collection of available
|
6
|
+
# Transformations. Every method is given a string as single argument
|
7
|
+
# and is expected to return a transformed string. The only exception
|
8
|
+
# from this is general rule is the replace method which also takes a
|
9
|
+
# replacement table.
|
10
|
+
#
|
11
|
+
# This enables chaining and eases extending the capabilities.
|
12
|
+
module Converters
|
13
|
+
end
|
14
|
+
end
|
data/lib/to_pass.rb
CHANGED
@@ -13,6 +13,7 @@ module ToPass
|
|
13
13
|
autoload :Base, 'lib/to_pass/base'
|
14
14
|
autoload :Cli, 'lib/to_pass/cli.rb'
|
15
15
|
autoload :Converter, 'lib/to_pass/converter'
|
16
|
+
autoload :ConverterReader, 'lib/to_pass/converter_reader'
|
17
|
+
autoload :Converters, 'lib/to_pass/converters'
|
16
18
|
autoload :Integration, 'lib/to_pass/integration'
|
17
|
-
autoload :StringConversions, 'lib/to_pass/string_conversions'
|
18
19
|
end
|
data/test/fixtures/user_alg.yml
CHANGED
@@ -2,13 +2,13 @@ desc: Test Algorithm
|
|
2
2
|
name: Test
|
3
3
|
sentence:
|
4
4
|
- first_chars
|
5
|
-
-
|
6
|
-
-
|
5
|
+
- replace: chars
|
6
|
+
- replace: symbols
|
7
7
|
- collapse_chars
|
8
8
|
word:
|
9
|
-
-
|
10
|
-
-
|
11
|
-
|
9
|
+
- replace: chars
|
10
|
+
- replace: symbols
|
11
|
+
replacements:
|
12
12
|
symbols:
|
13
13
|
p: '%'
|
14
14
|
s: '/'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# vim:ft=ruby:enc=utf-8
|
3
|
+
|
4
|
+
module ToPass::Converters
|
5
|
+
# replace the string "USER" with the current username
|
6
|
+
class Userize
|
7
|
+
def self.convert(string) # :nodoc:
|
8
|
+
username = if `which whoami`
|
9
|
+
`whoami`.chomp
|
10
|
+
else
|
11
|
+
"thecurrentuser"
|
12
|
+
end
|
13
|
+
|
14
|
+
string.gsub("USER",username)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/test/helper.rb
CHANGED
@@ -27,10 +27,16 @@ Test::Unit::TestCase.class_eval do
|
|
27
27
|
|
28
28
|
|
29
29
|
def with_algorithm_in_user_dir
|
30
|
-
`mkdir -p
|
30
|
+
`mkdir -p ~/.to_pass/algorithms; cp -f #{File.dirname(__FILE__)}/fixtures/user_alg.yml ~/.to_pass/algorithms/user_alg.yml`
|
31
31
|
yield
|
32
32
|
`rm ~/.to_pass/algorithms/user_alg.yml`
|
33
33
|
end
|
34
|
+
|
35
|
+
def with_converters_in_user_dir
|
36
|
+
`mkdir -p ~/.to_pass/converters; cp -f #{File.dirname(__FILE__)}/fixtures/user_converter.rb ~/.to_pass/converters/userize.rb`
|
37
|
+
yield
|
38
|
+
`rm ~/.to_pass/converters/userize.rb`
|
39
|
+
end
|
34
40
|
end
|
35
41
|
|
36
42
|
require 'lib/to_pass'
|
@@ -17,6 +17,11 @@ class TestAlgorithmReader < Test::Unit::TestCase
|
|
17
17
|
assert_kind_of Hash, klass.load(:basic_de)
|
18
18
|
end
|
19
19
|
|
20
|
+
def test_discover
|
21
|
+
assert_respond_to klass, :discover
|
22
|
+
assert_kind_of Array, klass.discover
|
23
|
+
end
|
24
|
+
|
20
25
|
def test_has_load_path
|
21
26
|
assert_respond_to reader, :load_path
|
22
27
|
assert_kind_of Array, reader.load_path
|
@@ -25,7 +30,7 @@ class TestAlgorithmReader < Test::Unit::TestCase
|
|
25
30
|
def test_load_path_contains_standard_dirs
|
26
31
|
dirs = [
|
27
32
|
'~/.to_pass/algorithms' ,
|
28
|
-
"#{File.dirname(__FILE__)}/../lib/algorithms"
|
33
|
+
"#{File.dirname(__FILE__)}/../lib/to_pass/algorithms"
|
29
34
|
]
|
30
35
|
|
31
36
|
Pathname.any_instance.expects(:exist?).times(dirs.size).returns(true)
|
data/test/test_cli.rb
CHANGED
@@ -24,6 +24,18 @@ class TestCli < Test::Unit::TestCase
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
def test_cli_usage_with_pipe_input
|
28
|
+
assert_nothing_raised do
|
29
|
+
assert_equal 't35t', `echo "test" | bin/to_pass --no-pipe`.chomp
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_cli_usage_with_pipe_output
|
34
|
+
assert_nothing_raised do
|
35
|
+
assert_equal 't35t', `bin/to_pass test --pipe`
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
27
39
|
|
28
40
|
def test_cli_usage_with_user_algorithm
|
29
41
|
with_algorithm_in_user_dir do
|
data/test/test_converter.rb
CHANGED
@@ -25,33 +25,34 @@ class TestConverter < Test::Unit::TestCase
|
|
25
25
|
# mock-tests to ensure presence and calling of protected methods
|
26
26
|
def test_replace
|
27
27
|
assert_respond_to converter, :replace
|
28
|
-
converter.expects(:replace).once
|
28
|
+
converter.expects(:apply_rule).with("test", {'replace'=>'special'}).once
|
29
29
|
|
30
30
|
converter.convert("test")
|
31
31
|
end
|
32
32
|
def test_swapcase
|
33
33
|
converter({'word' => ['swapcase']})
|
34
34
|
assert_respond_to converter, :swapcase
|
35
|
-
converter.expects(:swapcase).once
|
35
|
+
converter.expects(:apply_rule).with("test", 'swapcase' ).once
|
36
36
|
converter.convert("test")
|
37
37
|
end
|
38
38
|
def test_first_chars
|
39
39
|
converter({'sentence' => ['first_chars']})
|
40
40
|
assert_respond_to converter, :first_chars
|
41
|
-
converter.expects(:first_chars).once
|
41
|
+
converter.expects(:apply_rule).with("test test", 'first_chars').once
|
42
42
|
converter.convert("test test")
|
43
43
|
end
|
44
44
|
def test_collapse_chars
|
45
45
|
converter({'sentence' => ['collapse_chars']})
|
46
46
|
assert_respond_to converter, :collapse_chars
|
47
|
-
converter.expects(:collapse_chars).once
|
47
|
+
converter.expects(:apply_rule).with("test test", 'collapse_chars').once
|
48
48
|
converter.convert("test test")
|
49
49
|
end
|
50
50
|
|
51
|
+
|
51
52
|
# more complex/real-life setups
|
52
53
|
def test_multiple_rules
|
53
54
|
converter(basic_rules.merge({
|
54
|
-
'word' => [{'
|
55
|
+
'word' => [{'replace' => 'special'}, 'swapcase']
|
55
56
|
}))
|
56
57
|
|
57
58
|
assert_equal( "t35T", converter.convert('test'))
|
@@ -67,6 +68,34 @@ class TestConverter < Test::Unit::TestCase
|
|
67
68
|
Pferd auf dem Flur"))
|
68
69
|
end
|
69
70
|
|
71
|
+
|
72
|
+
# actual result-testing
|
73
|
+
def test_replacement
|
74
|
+
rules = {
|
75
|
+
'replacements' => {
|
76
|
+
'numbers' => {
|
77
|
+
:e => 3,
|
78
|
+
:s => 5
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
result = converter(rules).send(:apply_rule, "test", {'replace'=>'numbers'})
|
83
|
+
assert_equal "t35t", result
|
84
|
+
end
|
85
|
+
def test_case_swapping
|
86
|
+
assert_equal "tEsT", converter.send(:apply_rule, "test", 'swapcase')
|
87
|
+
end
|
88
|
+
def test_case_swapping_ignores_numbers
|
89
|
+
assert_equal "tEsT4fUn", converter.send(:apply_rule, "test4fun", 'swapcase')
|
90
|
+
assert_equal "fUn4TeSt", converter.send(:apply_rule, "fun4test", 'swapcase')
|
91
|
+
end
|
92
|
+
def test_char_collapsing
|
93
|
+
assert_equal "abc", converter.send(:apply_rule, "a b c", 'collapse_chars')
|
94
|
+
end
|
95
|
+
def test_select_first_chars
|
96
|
+
assert_equal "t a t f t", converter.send(:apply_rule, "test all the fucking time", 'first_chars')
|
97
|
+
end
|
98
|
+
|
70
99
|
protected
|
71
100
|
|
72
101
|
def converter(rules = basic_rules)
|
@@ -75,8 +104,8 @@ Pferd auf dem Flur"))
|
|
75
104
|
|
76
105
|
def basic_rules
|
77
106
|
{
|
78
|
-
'word' => [{ '
|
79
|
-
'
|
107
|
+
'word' => [{ 'replace' => 'special' }],
|
108
|
+
'replacements' => {
|
80
109
|
'special' => {
|
81
110
|
'e' => '3',
|
82
111
|
's' => '5'
|
@@ -86,8 +115,8 @@ Pferd auf dem Flur"))
|
|
86
115
|
end
|
87
116
|
def complex_rules
|
88
117
|
{
|
89
|
-
'sentence' => [{'
|
90
|
-
'
|
118
|
+
'sentence' => [{'replace'=>'words'},'first_chars','collapse_chars',{'replace'=>'symbols'}],
|
119
|
+
'replacements' => {
|
91
120
|
'words' => { 'ein' => '1' },
|
92
121
|
'symbols' => { 'a' => '@' }
|
93
122
|
}
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# vim:ft=ruby:enc=utf-8
|
3
|
+
|
4
|
+
require File.dirname(__FILE__)+'/helper'
|
5
|
+
|
6
|
+
class TestConverterReader < Test::Unit::TestCase
|
7
|
+
test_presence ToPass::ConverterReader
|
8
|
+
|
9
|
+
def test_load
|
10
|
+
assert_respond_to reader, :load
|
11
|
+
assert_kind_of Class, reader.load(:replace)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_discover
|
15
|
+
assert_respond_to reader, :discover
|
16
|
+
assert_kind_of Array, reader.discover
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_has_load_path
|
20
|
+
assert_respond_to reader, :load_path
|
21
|
+
assert_kind_of Array, reader.load_path
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_knows_loaded_converters
|
25
|
+
assert_respond_to reader, :loaded
|
26
|
+
assert_kind_of Array, reader.loaded
|
27
|
+
assert_equal 0, reader.loaded.size
|
28
|
+
|
29
|
+
reader.load(:replace)
|
30
|
+
reader.load(:first_chars)
|
31
|
+
|
32
|
+
assert_equal 2, reader.loaded.size
|
33
|
+
assert_equal :replace, reader.loaded.first
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_load_path_contains_standard_dirs
|
37
|
+
dirs = [
|
38
|
+
'~/.to_pass/converters',
|
39
|
+
"#{File.dirname(__FILE__)}/../lib/to_pass/converters"
|
40
|
+
]
|
41
|
+
|
42
|
+
Pathname.any_instance.expects(:exist?).times(dirs.size).returns(true)
|
43
|
+
|
44
|
+
dirs.each do |reldir|
|
45
|
+
dir = Pathname.new(reldir).expand_path
|
46
|
+
assert( reader.load_path.include?(dir), "#{reader.load_path.inspect} should include #{dir.inspect}" )
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_loads_from_user_dir
|
51
|
+
with_converters_in_user_dir do
|
52
|
+
assert_kind_of Class, reader.load(:userize), "Converter 'Userize' should have been found"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def klass
|
59
|
+
ToPass::ConverterReader
|
60
|
+
end
|
61
|
+
def reader
|
62
|
+
@reader ||= klass.new
|
63
|
+
end
|
64
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: to_pass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
- 2
|
9
8
|
- 4
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Matthias Viehweger
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-06-
|
18
|
+
date: 2010-06-30 00:00:00 +02:00
|
19
19
|
default_executable: to_pass
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -66,23 +66,30 @@ files:
|
|
66
66
|
- TODO
|
67
67
|
- VERSION
|
68
68
|
- bin/to_pass
|
69
|
-
- lib/algorithms/basic_de.yml
|
70
|
-
- lib/algorithms/basic_en.yml
|
71
69
|
- lib/to_pass.rb
|
72
70
|
- lib/to_pass/algorithm_reader.rb
|
71
|
+
- lib/to_pass/algorithms/basic_de.yml
|
72
|
+
- lib/to_pass/algorithms/basic_en.yml
|
73
73
|
- lib/to_pass/base.rb
|
74
74
|
- lib/to_pass/cli.rb
|
75
75
|
- lib/to_pass/converter.rb
|
76
|
+
- lib/to_pass/converter_reader.rb
|
77
|
+
- lib/to_pass/converters.rb
|
78
|
+
- lib/to_pass/converters/collapse_chars.rb
|
79
|
+
- lib/to_pass/converters/first_chars.rb
|
80
|
+
- lib/to_pass/converters/replace.rb
|
81
|
+
- lib/to_pass/converters/swapcase.rb
|
76
82
|
- lib/to_pass/integration.rb
|
77
|
-
- lib/to_pass/string_conversions.rb
|
78
83
|
- test/fixtures/user_alg.yml
|
84
|
+
- test/fixtures/user_converter.rb
|
79
85
|
- test/helper.rb
|
80
86
|
- test/test_algorithm_reader.rb
|
81
87
|
- test/test_base.rb
|
82
88
|
- test/test_cli.rb
|
83
89
|
- test/test_converter.rb
|
90
|
+
- test/test_converter_reader.rb
|
91
|
+
- test/test_converters.rb
|
84
92
|
- test/test_integration.rb
|
85
|
-
- test/test_string_conversions.rb
|
86
93
|
has_rdoc: true
|
87
94
|
homepage: http://github.com/kronn/to_pass
|
88
95
|
licenses: []
|
@@ -118,10 +125,12 @@ signing_key:
|
|
118
125
|
specification_version: 3
|
119
126
|
summary: generate password from words or sentences
|
120
127
|
test_files:
|
128
|
+
- test/fixtures/user_converter.rb
|
121
129
|
- test/helper.rb
|
122
130
|
- test/test_algorithm_reader.rb
|
123
131
|
- test/test_base.rb
|
124
132
|
- test/test_cli.rb
|
125
133
|
- test/test_converter.rb
|
134
|
+
- test/test_converter_reader.rb
|
135
|
+
- test/test_converters.rb
|
126
136
|
- test/test_integration.rb
|
127
|
-
- test/test_string_conversions.rb
|
@@ -1,54 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
# vim:ft=ruby:enc=utf-8
|
3
|
-
|
4
|
-
module ToPass
|
5
|
-
# The StringConversions-Module is a collection of available
|
6
|
-
# Transformations. Every method is given a string as single argument
|
7
|
-
# and is expected to return a transformed string. The only exception
|
8
|
-
# from this is general rule is the replace method which also takes a
|
9
|
-
# replacement table.
|
10
|
-
#
|
11
|
-
# This enables chaining and eases extending the capabilities.
|
12
|
-
module StringConversions
|
13
|
-
# all the blanks are removed.
|
14
|
-
#
|
15
|
-
# this is useful if you convert a sentence into a password.
|
16
|
-
def collapse_chars(string)
|
17
|
-
string = string.split(' ').join('')
|
18
|
-
end
|
19
|
-
|
20
|
-
# reduces every word to its first character, preserving case
|
21
|
-
def first_chars(string)
|
22
|
-
string.split(' ').map do |word|
|
23
|
-
word[0].chr
|
24
|
-
end.join(' ')
|
25
|
-
end
|
26
|
-
|
27
|
-
# alternate case of letter (not numbers)
|
28
|
-
def swapcase(string)
|
29
|
-
pwd = ""
|
30
|
-
last_upcase = true
|
31
|
-
|
32
|
-
string.each_char do |char|
|
33
|
-
char = if char.between?("0", "9")
|
34
|
-
char
|
35
|
-
elsif last_upcase
|
36
|
-
last_upcase = false
|
37
|
-
char.downcase
|
38
|
-
else
|
39
|
-
last_upcase = true
|
40
|
-
char.upcase
|
41
|
-
end
|
42
|
-
pwd << char
|
43
|
-
end
|
44
|
-
pwd
|
45
|
-
end
|
46
|
-
|
47
|
-
# perform replacements on a string, based on a replacment table
|
48
|
-
def replace(string, table)
|
49
|
-
table.inject(string) do |pwd, map|
|
50
|
-
pwd = pwd.gsub(/#{map[0].to_s}/, map[1].to_s)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
# vim:ft=ruby:enc=utf-8
|
3
|
-
|
4
|
-
require File.dirname(__FILE__)+'/helper'
|
5
|
-
|
6
|
-
class TestStringConversion < Test::Unit::TestCase
|
7
|
-
def test_replacement
|
8
|
-
result = converter.replace("test", {
|
9
|
-
:e => 3,
|
10
|
-
:s => 5
|
11
|
-
})
|
12
|
-
assert_equal "t35t", result
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_case_swapping
|
16
|
-
assert_equal "tEsT", converter.swapcase("test")
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_case_swapping_ignores_numbers
|
20
|
-
assert_equal "tEsT4fUn", converter.swapcase("test4fun")
|
21
|
-
|
22
|
-
assert_equal "fUn4TeSt", converter.swapcase("fun4test")
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_char_collapsing
|
26
|
-
assert_equal "abc", converter.collapse_chars("a b c")
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_select_first_chars
|
30
|
-
assert_equal "t a t f t", converter.first_chars('test all the fucking time')
|
31
|
-
end
|
32
|
-
|
33
|
-
protected
|
34
|
-
|
35
|
-
def converter
|
36
|
-
klass = Class.new
|
37
|
-
klass.send(:extend, ToPass::StringConversions)
|
38
|
-
klass
|
39
|
-
end
|
40
|
-
end
|