to_pass 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +48 -0
- data/Rakefile +53 -0
- data/TODO +9 -0
- data/VERSION +1 -0
- data/bin/to_pass +47 -0
- data/lib/algorithms/basic_de.yml +30 -0
- data/lib/algorithms/basic_en.yml +32 -0
- data/lib/to_pass/algorithm_reader.rb +47 -0
- data/lib/to_pass/base.rb +20 -0
- data/lib/to_pass/converter.rb +62 -0
- data/lib/to_pass/integration.rb +13 -0
- data/lib/to_pass/string_conversions.rb +51 -0
- data/lib/to_pass.rb +14 -0
- data/test/helper.rb +26 -0
- data/test/test_algorithm_reader.rb +44 -0
- data/test/test_base.rb +20 -0
- data/test/test_converter.rb +93 -0
- data/test/test_integration.rb +30 -0
- data/test/test_string_conversions.rb +37 -0
- metadata +123 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009-2010 Matthias Viehweger
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
= to_pass
|
2
|
+
|
3
|
+
== Transformation of a String to a Password.
|
4
|
+
|
5
|
+
Passwords should be easy to remember and hard to guess. One technique is to
|
6
|
+
have a sentence which can be easily remembered transformed to a password.
|
7
|
+
|
8
|
+
This library encapsulates that and satisfies different usage scenarios.
|
9
|
+
Currently, only two algorithms are provided. But they are YAML-Files, so it's
|
10
|
+
extensible.
|
11
|
+
|
12
|
+
== Usage
|
13
|
+
|
14
|
+
=== IRB
|
15
|
+
|
16
|
+
ToPass::Integration provides a to_pass Method which transforms a sentence to a
|
17
|
+
password.
|
18
|
+
|
19
|
+
irb> require 'lib/to_pass'
|
20
|
+
irb> String.send(:include, ToPass::Integration)
|
21
|
+
irb> "Da steht ein Pferd auf dem Flur".to_pass
|
22
|
+
# => "Ds1P@dF"
|
23
|
+
|
24
|
+
=== CLI
|
25
|
+
|
26
|
+
$ to_pass "test" # => t35t
|
27
|
+
$ to_pass "there is one problem for us, too" -a basic_en # => ti1p4u2
|
28
|
+
|
29
|
+
=== CLI with Pipes
|
30
|
+
|
31
|
+
This example is Mac OSX-centric, but you should get the point.
|
32
|
+
|
33
|
+
$ echo "test" | to_pass | pbcopy
|
34
|
+
|
35
|
+
== Note on Patches/Pull Requests
|
36
|
+
|
37
|
+
* Fork the project.
|
38
|
+
* Make your feature addition or bug fix.
|
39
|
+
* Add tests for it. This is important so I don't break it in a
|
40
|
+
future version unintentionally.
|
41
|
+
* Commit, do not mess with rakefile, version, or history.
|
42
|
+
(if you want to have your own version, that is fine but bump version in a
|
43
|
+
commit by itself I can ignore when I pull)
|
44
|
+
* Send me a pull request. Bonus points for topic branches.
|
45
|
+
|
46
|
+
== Copyright
|
47
|
+
|
48
|
+
Copyright (c) 2010 Matthias Viehweger. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# vim:ft=ruby:enc=utf-8
|
3
|
+
|
4
|
+
# # enable trace to get better error output
|
5
|
+
# Rake.application.options.trace = true
|
6
|
+
|
7
|
+
# jeweler task
|
8
|
+
begin
|
9
|
+
require 'jeweler'
|
10
|
+
Jeweler::Tasks.new do |gem|
|
11
|
+
gem.name = "to_pass"
|
12
|
+
gem.summary = "generate password from words or sentences"
|
13
|
+
gem.description = %Q{Passwords should be easy to remember and hard to guess.
|
14
|
+
One technique is to have a sentence which can be easily remembered transformed to a password.}
|
15
|
+
gem.email = "kronn@kronn.de"
|
16
|
+
gem.homepage = "http://github.com/kronn/to_pass"
|
17
|
+
gem.authors = ["Matthias Viehweger"]
|
18
|
+
|
19
|
+
gem.add_development_dependency 'mocha'
|
20
|
+
gem.add_development_dependency 'sdoc'
|
21
|
+
end
|
22
|
+
Jeweler::GemcutterTasks.new
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
25
|
+
end
|
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')
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "run tests"
|
40
|
+
task :test, :needs => [:check_dependencies] do
|
41
|
+
# optional libraries
|
42
|
+
%w[ redgreen ].each do |lib|
|
43
|
+
begin
|
44
|
+
require lib
|
45
|
+
rescue LoadError
|
46
|
+
end
|
47
|
+
end
|
48
|
+
( ['test/unit', 'test/helper'] + Dir['test/test_*.rb'] ).each do |file|
|
49
|
+
require file
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
task :default => :test
|
data/TODO
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
UP NEXT
|
2
|
+
============================================================================
|
3
|
+
- test and enble class methods of Converter-class
|
4
|
+
|
5
|
+
SOMEDAY
|
6
|
+
============================================================================
|
7
|
+
- move decision wether a string is a word or not into algorithm definition.
|
8
|
+
- make conversion-functions more pluggable
|
9
|
+
- test on windows
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.2
|
data/bin/to_pass
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# vim:ft=ruby:enc=utf-8
|
4
|
+
|
5
|
+
base_path = ( File.expand_path(File.dirname(__FILE__)+'/..') )
|
6
|
+
$LOAD_PATH << base_path unless $LOAD_PATH.include?(base_path)
|
7
|
+
|
8
|
+
require 'optparse'
|
9
|
+
require 'lib/to_pass'
|
10
|
+
|
11
|
+
# parse options
|
12
|
+
options = {
|
13
|
+
:pipe_usage => ARGV[0].nil?,
|
14
|
+
:algorithm => 'basic_de'
|
15
|
+
}
|
16
|
+
|
17
|
+
OptionParser.new do |opts|
|
18
|
+
opts.banner = "Usage: #{__FILE__} [options] passphrase"
|
19
|
+
opts.separator ""
|
20
|
+
|
21
|
+
opts.on('-a', '--algorithm ALGORITM', "use specified algorithm for transformation") do |value|
|
22
|
+
options[:algorithm] = value
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.separator ""
|
26
|
+
|
27
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
28
|
+
puts opts
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
end.parse!
|
32
|
+
|
33
|
+
# get input string
|
34
|
+
string= unless options[:pipe_usage]
|
35
|
+
ARGV[0]
|
36
|
+
else
|
37
|
+
$stdin.read.chomp
|
38
|
+
end
|
39
|
+
|
40
|
+
# perform "heavy" work
|
41
|
+
password = ToPass::Base.new( string, options[:algorithm] ).to_s
|
42
|
+
|
43
|
+
if options[:pipe_usage]
|
44
|
+
$stdout << password
|
45
|
+
else
|
46
|
+
puts password
|
47
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
desc: Basic Algorithm with a german usage in mind
|
2
|
+
name: Basic (german)
|
3
|
+
sentence:
|
4
|
+
- table: words
|
5
|
+
- first_chars
|
6
|
+
- table: symbols
|
7
|
+
- collapse_chars
|
8
|
+
word:
|
9
|
+
- table: chars
|
10
|
+
- table: symbols
|
11
|
+
tables:
|
12
|
+
words:
|
13
|
+
ein: 1
|
14
|
+
eine: 1
|
15
|
+
zwei: 2
|
16
|
+
drei: 3
|
17
|
+
vier: 4
|
18
|
+
fuenf: 5
|
19
|
+
sechs: 6
|
20
|
+
sieben: 7
|
21
|
+
acht: 8
|
22
|
+
neun: 9
|
23
|
+
symbols:
|
24
|
+
a: '@'
|
25
|
+
chars:
|
26
|
+
a: 4
|
27
|
+
e: 3
|
28
|
+
i: 1
|
29
|
+
o: 0
|
30
|
+
s: 5
|
@@ -0,0 +1,32 @@
|
|
1
|
+
desc: Basic Algorithm with a english usage in mind
|
2
|
+
name: Basic (english)
|
3
|
+
sentence:
|
4
|
+
- table: words
|
5
|
+
- first_chars
|
6
|
+
- table: symbols
|
7
|
+
- collapse_chars
|
8
|
+
word:
|
9
|
+
- table: chars
|
10
|
+
- table: symbols
|
11
|
+
tables:
|
12
|
+
words:
|
13
|
+
one: 1
|
14
|
+
single: 1
|
15
|
+
two: 2
|
16
|
+
too: 2
|
17
|
+
three: 3
|
18
|
+
four: 4
|
19
|
+
for: 4
|
20
|
+
five: 5
|
21
|
+
six: 6
|
22
|
+
seven: 7
|
23
|
+
eight: 8
|
24
|
+
nine: 9
|
25
|
+
symbols:
|
26
|
+
a: '@'
|
27
|
+
chars:
|
28
|
+
a: 4
|
29
|
+
e: 3
|
30
|
+
i: 1
|
31
|
+
o: 0
|
32
|
+
s: 5
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
# The AlgorithmReader's primary API is the load the rules from a YAML-file
|
5
|
+
# into a Hash.
|
6
|
+
#
|
7
|
+
# Algorithms are searched in the following locations
|
8
|
+
#
|
9
|
+
# 1. ~/.to_pass/algorithms
|
10
|
+
# 2. bundled algorithms of gem
|
11
|
+
#
|
12
|
+
class ToPass::AlgorithmReader
|
13
|
+
attr_reader :load_path
|
14
|
+
|
15
|
+
def initialize(algorithm) # :nodoc:
|
16
|
+
@algorithm = algorithm
|
17
|
+
@load_path = []
|
18
|
+
[
|
19
|
+
'~/.to_pass/algorithms',
|
20
|
+
"#{File.dirname(__FILE__)}/../algorithms"
|
21
|
+
].each do |dir|
|
22
|
+
dir = Pathname.new(dir)
|
23
|
+
@load_path << dir.expand_path if dir.exist?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
# load an algorithm with a given identifier
|
29
|
+
def load(algorithm)
|
30
|
+
new(algorithm).load_from_file
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def load_from_file # :nodoc:
|
35
|
+
fn = load_path.map do |dir|
|
36
|
+
file = Pathname.new("#{dir}/#{@algorithm}.yml")
|
37
|
+
|
38
|
+
if file.exist?
|
39
|
+
file
|
40
|
+
else
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end.compact.first
|
44
|
+
|
45
|
+
YAML.load_file(fn.expand_path)
|
46
|
+
end
|
47
|
+
end
|
data/lib/to_pass/base.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module ToPass
|
2
|
+
# ToPass::Base is mostly a facade for the library.
|
3
|
+
#
|
4
|
+
# Given a string and a algorithm identifier, the right rules
|
5
|
+
# are loaded and applied to the string. With a simple "to_s",
|
6
|
+
# you can get the final password
|
7
|
+
class Base
|
8
|
+
# transform a string according to a certain algorithm
|
9
|
+
def initialize( string, algorithm )
|
10
|
+
rules = AlgorithmReader.load(algorithm)
|
11
|
+
converter = Converter.new( rules )
|
12
|
+
@password = converter.convert(string)
|
13
|
+
end
|
14
|
+
|
15
|
+
# return the generated password
|
16
|
+
def to_s
|
17
|
+
@password
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module ToPass
|
2
|
+
# converts a given string into a password-like word
|
3
|
+
#
|
4
|
+
# the string can be a word or a sentence. everthing which
|
5
|
+
# contains whitespace is considered a sentence
|
6
|
+
#
|
7
|
+
# a more complete description of the algorithm capabilities
|
8
|
+
# is still pending.
|
9
|
+
class Converter
|
10
|
+
# create a new converter, based on a set of conversion-rules
|
11
|
+
def initialize( rules )
|
12
|
+
@rules = rules
|
13
|
+
end
|
14
|
+
|
15
|
+
# convert a string into a password
|
16
|
+
def convert( string )
|
17
|
+
process(string, rules_for(string))
|
18
|
+
end
|
19
|
+
|
20
|
+
# class << self
|
21
|
+
# # convenience method to apply conversion rules to a string
|
22
|
+
# def apply(rules, string)
|
23
|
+
# new(rules).convert(string)
|
24
|
+
# end
|
25
|
+
# # convenience method to convert a string based on rules
|
26
|
+
# def convert(string, rules)
|
27
|
+
# new(rules).convert(string)
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
include StringConversions
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# return the applicable rules for a given string.
|
38
|
+
#
|
39
|
+
# everything which contains whitespace is considered a sentence,
|
40
|
+
# otherwise it is most likely a word.
|
41
|
+
def rules_for( string )
|
42
|
+
if string.include? ' ' or /\s/.match(string)
|
43
|
+
@rules['sentence']
|
44
|
+
else
|
45
|
+
@rules['word']
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# process the string, rule by rule
|
50
|
+
def process(string, rules)
|
51
|
+
rules.inject(string) do |pwd, rule|
|
52
|
+
if rule.is_a?(String) and respond_to?(rule.to_sym)
|
53
|
+
send(rule.to_sym, pwd)
|
54
|
+
elsif rule.is_a?(Hash) and rule.has_key?('table')
|
55
|
+
replace(pwd, @rules['tables'][rule.fetch('table')])
|
56
|
+
else
|
57
|
+
pwd
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Any Object can be a password, as long as it has a string representation.
|
2
|
+
#
|
3
|
+
# This Module provides a shortcut to the password-conversion.
|
4
|
+
#
|
5
|
+
# String.send(:include, ToPass::Integration)
|
6
|
+
# puts "Da steht ein Pferd auf dem Flur".to_pass => 'Ds1P@dF'
|
7
|
+
#
|
8
|
+
module ToPass::Integration
|
9
|
+
# simplified password-creation
|
10
|
+
def to_pass( algorithm = 'basic_de' )
|
11
|
+
ToPass::Base.new(self.to_s, algorithm).to_s
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module ToPass
|
2
|
+
# The StringConversions-Module is a collection of available
|
3
|
+
# Transformations. Every method is given a string as single argument
|
4
|
+
# and is expected to return a transformed string. The only exception
|
5
|
+
# from this is general rule is the replace method which also takes a
|
6
|
+
# replacement table.
|
7
|
+
#
|
8
|
+
# This enables chaining and eases extending the capabilities.
|
9
|
+
module StringConversions
|
10
|
+
# all the blanks are removed.
|
11
|
+
#
|
12
|
+
# this is useful if you convert a sentence into a password.
|
13
|
+
def collapse_chars(string)
|
14
|
+
string = string.split(' ').join('')
|
15
|
+
end
|
16
|
+
|
17
|
+
# reduces every word to its first character, preserving case
|
18
|
+
def first_chars(string)
|
19
|
+
string.split(' ').map do |word|
|
20
|
+
word[0].chr
|
21
|
+
end.join(' ')
|
22
|
+
end
|
23
|
+
|
24
|
+
# alternate case of letter (not numbers)
|
25
|
+
def swapcase(string)
|
26
|
+
pwd = ""
|
27
|
+
last_upcase = true
|
28
|
+
|
29
|
+
string.each_char do |char|
|
30
|
+
char = if char.between?("0", "9")
|
31
|
+
char
|
32
|
+
elsif last_upcase
|
33
|
+
last_upcase = false
|
34
|
+
char.downcase
|
35
|
+
else
|
36
|
+
last_upcase = true
|
37
|
+
char.upcase
|
38
|
+
end
|
39
|
+
pwd << char
|
40
|
+
end
|
41
|
+
pwd
|
42
|
+
end
|
43
|
+
|
44
|
+
# perform replacements on a string, based on a replacment table
|
45
|
+
def replace(string, table)
|
46
|
+
table.inject(string) do |pwd, map|
|
47
|
+
pwd = pwd.gsub(/#{map[0].to_s}/, map[1].to_s)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/to_pass.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Library to convert a String into a Password
|
2
|
+
module ToPass
|
3
|
+
# version of gem, read directly from the VERSION-File
|
4
|
+
VERSION = File.read(File.join(File.dirname(__FILE__), '../VERSION')).strip
|
5
|
+
|
6
|
+
# name of gem
|
7
|
+
APP_NAME = 'to_pass'
|
8
|
+
|
9
|
+
autoload :Converter, 'lib/to_pass/converter'
|
10
|
+
autoload :StringConversions, 'lib/to_pass/string_conversions'
|
11
|
+
autoload :Base, 'lib/to_pass/base'
|
12
|
+
autoload :Integration, 'lib/to_pass/integration'
|
13
|
+
autoload :AlgorithmReader, 'lib/to_pass/algorithm_reader'
|
14
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test/unit/testcase'
|
2
|
+
require 'test/unit' unless defined?(Test::Unit)
|
3
|
+
require 'mocha'
|
4
|
+
|
5
|
+
base_path = ( File.expand_path(File.dirname(__FILE__)+'/..') )
|
6
|
+
$LOAD_PATH << base_path unless $LOAD_PATH.include?(base_path)
|
7
|
+
|
8
|
+
Test::Unit::TestCase.class_eval do
|
9
|
+
def assert_class_defined(klass)
|
10
|
+
assert defined?(klass), "#{klass} should be defined"
|
11
|
+
assert_kind_of Class, klass, "#{klass} should be a class"
|
12
|
+
end
|
13
|
+
|
14
|
+
def assert_module_defined(modul)
|
15
|
+
assert defined?(modul), "#{modul} should be defined"
|
16
|
+
assert_kind_of Module, modul, "#{modul} should be a module"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.test_presence(klass)
|
20
|
+
define_method "test_presence" do
|
21
|
+
assert_class_defined klass
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'lib/to_pass'
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/helper'
|
2
|
+
|
3
|
+
class TestAlgorithmReader < Test::Unit::TestCase
|
4
|
+
test_presence ToPass::AlgorithmReader
|
5
|
+
|
6
|
+
def test_initialize
|
7
|
+
assert_nothing_raised do
|
8
|
+
klass.new( :basic_de )
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_load
|
13
|
+
assert_respond_to klass, :load
|
14
|
+
assert_kind_of Hash, klass.load(:basic_de)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_has_load_path
|
18
|
+
assert_respond_to reader, :load_path
|
19
|
+
assert_kind_of Array, reader.load_path
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_load_path_contains_standard_dirs
|
23
|
+
dirs = [
|
24
|
+
'~/.to_pass/algorithms' ,
|
25
|
+
"#{File.dirname(__FILE__)}/../lib/algorithms"
|
26
|
+
]
|
27
|
+
|
28
|
+
Pathname.any_instance.expects(:exist?).times(dirs.size).returns(true)
|
29
|
+
|
30
|
+
dirs.each do |reldir|
|
31
|
+
dir = Pathname.new(reldir).expand_path
|
32
|
+
assert( reader.load_path.include?(dir), "#{reader.load_path.inspect} should include #{dir.inspect}" )
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def klass
|
39
|
+
ToPass::AlgorithmReader
|
40
|
+
end
|
41
|
+
def reader(algorithm = :basic_de)
|
42
|
+
@reader ||= klass.new(algorithm)
|
43
|
+
end
|
44
|
+
end
|
data/test/test_base.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/helper'
|
2
|
+
|
3
|
+
class TestBase < Test::Unit::TestCase
|
4
|
+
test_presence ToPass::Base
|
5
|
+
|
6
|
+
def test_usage
|
7
|
+
assert_nothing_raised do
|
8
|
+
pwd = ToPass::Base.new("Da steht ein Pferd auf dem Flur", 'basic_de').to_s
|
9
|
+
assert_equal "Ds1P@dF", pwd
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_version
|
14
|
+
assert_equal Pathname.new("#{File.dirname(__FILE__)}/../VERSION").expand_path.read.chomp, ToPass::VERSION
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_appname
|
18
|
+
assert_equal "to_pass", ToPass::APP_NAME
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/helper'
|
2
|
+
|
3
|
+
class TestConverter < Test::Unit::TestCase
|
4
|
+
def teardown
|
5
|
+
@converter = nil
|
6
|
+
end
|
7
|
+
|
8
|
+
# basic presence and api-testing
|
9
|
+
test_presence ToPass::Converter
|
10
|
+
def test_instantiation
|
11
|
+
assert_nothing_raised do
|
12
|
+
ToPass::Converter.new({})
|
13
|
+
end
|
14
|
+
end
|
15
|
+
def test_convert
|
16
|
+
assert_respond_to converter, :convert
|
17
|
+
assert_nothing_raised do
|
18
|
+
converter.convert( "test" )
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# mock-tests to ensure presence and calling of protected methods
|
23
|
+
def test_replace
|
24
|
+
assert_respond_to converter, :replace
|
25
|
+
converter.expects(:replace).once
|
26
|
+
|
27
|
+
converter.convert("test")
|
28
|
+
end
|
29
|
+
def test_swapcase
|
30
|
+
converter({'word' => ['swapcase']})
|
31
|
+
assert_respond_to converter, :swapcase
|
32
|
+
converter.expects(:swapcase).once
|
33
|
+
converter.convert("test")
|
34
|
+
end
|
35
|
+
def test_first_chars
|
36
|
+
converter({'sentence' => ['first_chars']})
|
37
|
+
assert_respond_to converter, :first_chars
|
38
|
+
converter.expects(:first_chars).once
|
39
|
+
converter.convert("test test")
|
40
|
+
end
|
41
|
+
def test_collapse_chars
|
42
|
+
converter({'sentence' => ['collapse_chars']})
|
43
|
+
assert_respond_to converter, :collapse_chars
|
44
|
+
converter.expects(:collapse_chars).once
|
45
|
+
converter.convert("test test")
|
46
|
+
end
|
47
|
+
|
48
|
+
# more complex/real-life setups
|
49
|
+
def test_multiple_rules
|
50
|
+
converter(basic_rules.merge({
|
51
|
+
'word' => [{'table' => 'special'}, 'swapcase']
|
52
|
+
}))
|
53
|
+
|
54
|
+
assert_equal( "t35T", converter.convert('test'))
|
55
|
+
end
|
56
|
+
def test_sentence
|
57
|
+
converter(complex_rules)
|
58
|
+
assert_equal( "Ds1P@dF", converter.convert("Da steht ein Pferd auf dem Flur"))
|
59
|
+
end
|
60
|
+
def test_sentence_with_whitespace
|
61
|
+
converter(complex_rules)
|
62
|
+
assert_equal( "Ds1P@dF", converter.convert("Da steht ein
|
63
|
+
|
64
|
+
Pferd auf dem Flur"))
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
def converter(rules = basic_rules)
|
70
|
+
@converter ||= ToPass::Converter.new(rules)
|
71
|
+
end
|
72
|
+
|
73
|
+
def basic_rules
|
74
|
+
{
|
75
|
+
'word' => [{ 'table' => 'special' }],
|
76
|
+
'tables' => {
|
77
|
+
'special' => {
|
78
|
+
'e' => '3',
|
79
|
+
's' => '5'
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}
|
83
|
+
end
|
84
|
+
def complex_rules
|
85
|
+
{
|
86
|
+
'sentence' => [{'table'=>'words'},'first_chars','collapse_chars',{'table'=>'symbols'}],
|
87
|
+
'tables' => {
|
88
|
+
'words' => { 'ein' => '1' },
|
89
|
+
'symbols' => { 'a' => '@' }
|
90
|
+
}
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/helper'
|
2
|
+
|
3
|
+
class TestIntegration < Test::Unit::TestCase
|
4
|
+
def test_cli_usage_without_algorithm
|
5
|
+
assert_nothing_raised do
|
6
|
+
assert_equal "t35t", `bin/to_pass test`.chomp
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_cli_usage_with_algorithm
|
11
|
+
assert_nothing_raised do
|
12
|
+
assert_equal "ti1p4u2", `bin/to_pass 'there is one problem for us, too' -a basic_en`.chomp
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_cli_usage_with_pipes
|
17
|
+
assert_nothing_raised do
|
18
|
+
assert_equal 't35t', `echo "test" | bin/to_pass`
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_module_integration
|
23
|
+
assert_nothing_raised do
|
24
|
+
str = "test"
|
25
|
+
str.instance_eval "class << self; include ToPass::Integration; end"
|
26
|
+
|
27
|
+
assert_equal 't35t', str.to_pass
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/helper'
|
2
|
+
|
3
|
+
class TestStringConversion < Test::Unit::TestCase
|
4
|
+
def test_replacement
|
5
|
+
result = converter.replace("test", {
|
6
|
+
:e => 3,
|
7
|
+
:s => 5
|
8
|
+
})
|
9
|
+
assert_equal "t35t", result
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_case_swapping
|
13
|
+
assert_equal "tEsT", converter.swapcase("test")
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_case_swapping_ignores_numbers
|
17
|
+
assert_equal "tEsT4fUn", converter.swapcase("test4fun")
|
18
|
+
|
19
|
+
assert_equal "fUn4TeSt", converter.swapcase("fun4test")
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_char_collapsing
|
23
|
+
assert_equal "abc", converter.collapse_chars("a b c")
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_select_first_chars
|
27
|
+
assert_equal "t a t f t", converter.first_chars('test all the fucking time')
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def converter
|
33
|
+
klass = Class.new
|
34
|
+
klass.send(:extend, ToPass::StringConversions)
|
35
|
+
klass
|
36
|
+
end
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: to_pass
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 2
|
10
|
+
version: 0.2.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Matthias Viehweger
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-06-13 00:00:00 +02:00
|
19
|
+
default_executable: to_pass
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: mocha
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: sdoc
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
description: |-
|
50
|
+
Passwords should be easy to remember and hard to guess.
|
51
|
+
One technique is to have a sentence which can be easily remembered transformed to a password.
|
52
|
+
email: kronn@kronn.de
|
53
|
+
executables:
|
54
|
+
- to_pass
|
55
|
+
extensions: []
|
56
|
+
|
57
|
+
extra_rdoc_files:
|
58
|
+
- LICENSE
|
59
|
+
- README.rdoc
|
60
|
+
- TODO
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- LICENSE
|
64
|
+
- README.rdoc
|
65
|
+
- Rakefile
|
66
|
+
- TODO
|
67
|
+
- VERSION
|
68
|
+
- bin/to_pass
|
69
|
+
- lib/algorithms/basic_de.yml
|
70
|
+
- lib/algorithms/basic_en.yml
|
71
|
+
- lib/to_pass.rb
|
72
|
+
- lib/to_pass/algorithm_reader.rb
|
73
|
+
- lib/to_pass/base.rb
|
74
|
+
- lib/to_pass/converter.rb
|
75
|
+
- lib/to_pass/integration.rb
|
76
|
+
- lib/to_pass/string_conversions.rb
|
77
|
+
- test/helper.rb
|
78
|
+
- test/test_algorithm_reader.rb
|
79
|
+
- test/test_base.rb
|
80
|
+
- test/test_converter.rb
|
81
|
+
- test/test_integration.rb
|
82
|
+
- test/test_string_conversions.rb
|
83
|
+
has_rdoc: true
|
84
|
+
homepage: http://github.com/kronn/to_pass
|
85
|
+
licenses: []
|
86
|
+
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options:
|
89
|
+
- --charset=UTF-8
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
hash: 3
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
version: "0"
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
hash: 3
|
107
|
+
segments:
|
108
|
+
- 0
|
109
|
+
version: "0"
|
110
|
+
requirements: []
|
111
|
+
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 1.3.7
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: generate password from words or sentences
|
117
|
+
test_files:
|
118
|
+
- test/helper.rb
|
119
|
+
- test/test_algorithm_reader.rb
|
120
|
+
- test/test_base.rb
|
121
|
+
- test/test_converter.rb
|
122
|
+
- test/test_integration.rb
|
123
|
+
- test/test_string_conversions.rb
|