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 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
- %w[ rake/rdoctask sdoc ].each { |lib| require lib }
28
- Rake::RDocTask.new do |rdoc|
29
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
30
-
31
- rdoc.rdoc_dir = 'doc/rdoc'
32
- rdoc.title = "to_pass #{version}"
33
- rdoc.options << '--fmt' << 'shtml'
34
- rdoc.template = 'direct'
35
- rdoc.rdoc_files.include('README*')
36
- rdoc.rdoc_files.include('lib/**/*.rb')
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, :needs => [:check_dependencies] do
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
- - test and enble class methods of Converter-class
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.2.4
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 the load the rules from a YAML-file
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__)}/../algorithms"
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
- - table: words
4
+ - replace: words
5
5
  - first_chars
6
- - table: symbols
6
+ - replace: symbols
7
7
  - collapse_chars
8
8
  word:
9
- - table: chars
10
- - table: symbols
11
- tables:
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
- - table: words
4
+ - replace: words
5
5
  - first_chars
6
- - table: symbols
6
+ - replace: symbols
7
7
  - collapse_chars
8
8
  word:
9
- - table: chars
10
- - table: symbols
11
- tables:
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[:pipe_usage]
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 => 'basic_de'
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
- options[:pipe_usage] = ARGV[0].nil?
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[:pipe_usage]
61
+ unless @options[:pipe_in]
54
62
  ARGV[0]
55
63
  else
56
64
  $stdin.read.chomp
@@ -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
- protected
35
-
36
- include StringConversions
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
- if rule.is_a?(String) and respond_to?(rule.to_sym)
56
- send(rule.to_sym, pwd)
57
- elsif rule.is_a?(Hash) and rule.has_key?('table')
58
- replace(pwd, @rules['tables'][rule.fetch('table')])
59
- else
60
- pwd
61
- end
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 CollapseChars
3
+ class << self
4
+ # all the blanks are removed.
5
+ #
6
+ # this is useful if you convert a sentence into a password.
7
+ def collapse_chars(string)
8
+ string = string.split(' ').join('')
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module ToPass::Converters
2
+ class FirstChars
3
+ class << self
4
+ # reduces every word to its first character, preserving case
5
+ def first_chars(string)
6
+ string.split(' ').map do |word|
7
+ word[0].chr
8
+ end.join(' ')
9
+ end
10
+ end
11
+ end
12
+ 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
@@ -2,13 +2,13 @@ desc: Test Algorithm
2
2
  name: Test
3
3
  sentence:
4
4
  - first_chars
5
- - table: chars
6
- - table: symbols
5
+ - replace: chars
6
+ - replace: symbols
7
7
  - collapse_chars
8
8
  word:
9
- - table: chars
10
- - table: symbols
11
- tables:
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 ~/to_pass/algorithms; cp -f #{File.dirname(__FILE__)}/fixtures/user_alg.yml ~/.to_pass/algorithms/user_alg.yml`
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
@@ -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' => [{'table' => 'special'}, 'swapcase']
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' => [{ 'table' => 'special' }],
79
- 'tables' => {
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' => [{'table'=>'words'},'first_chars','collapse_chars',{'table'=>'symbols'}],
90
- 'tables' => {
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
@@ -0,0 +1,10 @@
1
+ # -*- coding: utf-8 -*-
2
+ # vim:ft=ruby:enc=utf-8
3
+
4
+ require File.dirname(__FILE__)+'/helper'
5
+
6
+ class TestConverters < Test::Unit::TestCase
7
+ def test_presence
8
+ assert_module_defined ToPass::Converters
9
+ end
10
+ 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: 31
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 2
9
8
  - 4
10
- version: 0.2.4
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-24 00:00:00 +02:00
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