purse 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ module Purse
2
+ class Note
3
+ attr_reader :path, :name, :encrypted, :options
4
+ attr_accessor :data
5
+
6
+ def initialize(path, name, data, options = {})
7
+ Purse.check_for_parameter('path', path)
8
+ Purse.check_for_parameter('name', name)
9
+ @path = path
10
+ @name = name
11
+ @options = options
12
+ if options[:encrypted]
13
+ @encrypted = data
14
+ else
15
+ @data = data
16
+ end
17
+ end
18
+
19
+ def self.load(path, name, options = {})
20
+ note = Note.new(path, name, nil)
21
+ raise MissingFile, "Tried to load #{note.file_path} but it does not exist" unless File.readable?(note.file_path)
22
+ encrypted_data = File.read(note.file_path)
23
+ Note.new(path, name, encrypted_data, options.merge(:encrypted => true))
24
+ end
25
+
26
+ def save(password)
27
+ Purse.check_for_parameter('password', password)
28
+ encrypt(password)
29
+ File.open(file_path, 'w') {|f| f << @encrypted }
30
+ self
31
+ end
32
+
33
+ def encrypt(password)
34
+ Purse.check_for_parameter('password', password)
35
+ blowfish = Crypt::Blowfish.new(password)
36
+ @encrypted = blowfish.encrypt_string(@data)
37
+ end
38
+
39
+ def decrypt(password)
40
+ Purse.check_for_parameter('password', password)
41
+ blowfish = Crypt::Blowfish.new(password)
42
+ @data = blowfish.decrypt_string(@encrypted)
43
+ end
44
+
45
+ def encrypted?
46
+ @encrypted && (!@data || @data.blank?)
47
+ end
48
+
49
+ def delete
50
+ File.unlink(file_path)
51
+ end
52
+
53
+ def file_path
54
+ File.join(path, file_name)
55
+ end
56
+
57
+ def file_name
58
+ "#{name}.note"
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,80 @@
1
+ module Purse
2
+ class Pocket
3
+ attr_reader :path
4
+
5
+ def initialize(path)
6
+ Purse.check_for_parameter('path', path)
7
+ @path = File.expand_path(path)
8
+ end
9
+
10
+ def init
11
+ FileUtils.mkdir_p(@path) unless File.readable?(@path)
12
+ git
13
+ end
14
+
15
+ def delete
16
+ FileUtils.rm_rf(@path)
17
+ end
18
+
19
+ def find(name)
20
+ Purse.check_for_parameter('name', name)
21
+ note = notes.find {|note| note.name == name }
22
+ note ? note : raise(Purse::MissingFile, "Could note find the note named #{note}")
23
+ end
24
+
25
+ def edit(name)
26
+ Purse.check_for_parameter('name', name)
27
+ begin
28
+ note = find(name)
29
+ rescue Purse::MissingFile
30
+ note = Note.new(path, name, nil)
31
+ end
32
+ yield(note)
33
+ @notes = load_notes
34
+ end
35
+
36
+ def notes
37
+ @notes ||= load_notes
38
+ end
39
+
40
+ def notes_paths
41
+ Dir[File.join(@path, '*.note')]
42
+ end
43
+
44
+ def load_notes
45
+ notes_paths.collect {|note_path| Note.load(File.dirname(note_path), File.basename(note_path, '.note'))}
46
+ end
47
+
48
+ def re_encrypt(password)
49
+ Purse.check_for_parameter('password', password)
50
+ notes.collect {|n| n.save(password) }
51
+ end
52
+
53
+ def commit
54
+ git.add('.')
55
+ return if git.status.changed.empty?
56
+ git.commit_all("Changes via Purse #{Time.now}")
57
+ end
58
+
59
+ def remote
60
+ git.remotes.first
61
+ end
62
+
63
+ def set_remote(remote_url)
64
+ git.add_remote('origin', remote_url)
65
+ end
66
+
67
+ def push
68
+ git.push('origin')
69
+ end
70
+
71
+ def pull
72
+ git.pull('origin')
73
+ end
74
+
75
+ protected
76
+ def git
77
+ @git ||= Git.init(@path)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,57 @@
1
+ module Purse
2
+ class Settings
3
+
4
+ class << self
5
+ def default_path
6
+ File.join(File.expand_path('~'), '.purse', 'settings.yml')
7
+ end
8
+
9
+ def path
10
+ @path ||= default_path
11
+ end
12
+
13
+ def path=(new_path)
14
+ raise MissingParameter unless new_path.is_a?(String)
15
+ @path = new_path
16
+ @loaded = false
17
+ end
18
+
19
+ def load
20
+ save unless File.readable?(path)
21
+ @settings = YAML.load_file(path)
22
+ @loaded = true
23
+ end
24
+
25
+ def loaded?
26
+ @loaded ||= false
27
+ end
28
+
29
+ def save
30
+ FileUtils.mkdir_p(File.dirname(path))
31
+ File.open(path, 'w') {|f| f << YAML::dump(settings) }
32
+ end
33
+
34
+ def get(key)
35
+ load unless loaded?
36
+ settings[key.to_s]
37
+ end
38
+
39
+ def set(key, value, should_save = true)
40
+ settings[key.to_s] = value
41
+ save if should_save
42
+ end
43
+
44
+ def settings
45
+ @settings ||= {}
46
+ end
47
+
48
+ def settings=(new_settings)
49
+ return unless new_settings.is_a?(Hash)
50
+ new_settings.each do |k, v|
51
+ set(k, v, false)
52
+ end
53
+ save
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,9 @@
1
+ module Purse
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,51 @@
1
+ require 'test_helper.rb'
2
+
3
+ class TestCli < Test::Unit::TestCase
4
+
5
+ context "Purse" do
6
+ context "Cli" do
7
+ context "run" do
8
+ setup do
9
+ HighLine.any_instance.stubs(:say)
10
+ @pocketname = 'test_purse_data'
11
+ end
12
+
13
+
14
+ # purse pursename #=> initialize or pull
15
+ context "purse pursename" do
16
+ should "call list" do
17
+ Cli.expects(:list).with(@pocketname).once
18
+ Cli.run([@pocketname])
19
+ end
20
+ end
21
+
22
+ # purse pursename notename
23
+ context "purse pursename notename" do
24
+
25
+ context "if the note exists" do
26
+ should "call init then call find and then display" do
27
+ notename = 'test123'
28
+ Cli.expects(:find).with(@pocketname,notename).once
29
+ Cli.run([@pocketname, notename])
30
+ end
31
+ end
32
+ end
33
+
34
+ # purse pursename notename --edit #=> open in EDITOR save and push
35
+ context "purse pursename notename --edit" do
36
+ should "call init edit" do
37
+ notename = 'jagger'
38
+ Cli.expects(:edit).with(@pocketname,notename).once
39
+ Cli.run([@pocketname, notename, '--edit'])
40
+ end
41
+ end
42
+
43
+ # purse pursename push
44
+ # purse pursename pull
45
+ # purse settings/ purse # rerun settings
46
+
47
+
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,206 @@
1
+ require 'test_helper.rb'
2
+
3
+ class TestNote < Test::Unit::TestCase
4
+
5
+ context "Purse" do
6
+ context "Note" do
7
+
8
+ context "an instance" do
9
+ setup do
10
+ @path = purse_path
11
+ @note = Note.new(@path, 'sander', 'Nonsense', :method => :blowfish, :store_as => :yaml)
12
+ end
13
+
14
+ context "new" do
15
+
16
+ should "require path" do
17
+ assert_raise(MissingParameter) do
18
+ Note.new(nil,'sander','Sander nonsense')
19
+ end
20
+ end
21
+
22
+ should "require name" do
23
+ assert_raise(MissingParameter) do
24
+ Note.new(purse_path, '', 'Sander nonsense')
25
+ end
26
+ end
27
+
28
+ context "initializing with regular data" do
29
+ should "set @path" do
30
+ assert_equal @path, @note.path
31
+ end
32
+
33
+ should "set @name" do
34
+ assert_equal 'sander', @note.name
35
+ end
36
+
37
+ should "set @data" do
38
+ assert_equal 'Nonsense', @note.data
39
+ end
40
+
41
+ should "save extra args as options" do
42
+ assert @note.options.is_a?(Hash)
43
+ assert_equal :blowfish, @note.options[:method]
44
+ end
45
+ end
46
+
47
+ context "initializing with encrypted data" do
48
+ setup do
49
+ @note = Note.new(purse_path, 'sander', 'ENCRYPTED DATA', :encrypted => true)
50
+ end
51
+
52
+ should "set @path" do
53
+ assert_equal purse_path, @note.path
54
+ end
55
+
56
+ should "set @name" do
57
+ assert_equal 'sander', @note.name
58
+ end
59
+
60
+ should "not set @data" do
61
+ assert_nil @note.data
62
+ end
63
+
64
+ should "set @encrypted" do
65
+ assert_equal 'ENCRYPTED DATA', @note.encrypted
66
+ end
67
+ end
68
+ end
69
+
70
+ context "file_name" do
71
+ should "return #name.note" do
72
+ assert_equal @note.name + '.note', @note.file_name
73
+ end
74
+ end
75
+
76
+ context "file_path" do
77
+ should "return path/name.note" do
78
+ assert_equal File.join(@note.path, @note.name + '.note'), @note.file_path
79
+ end
80
+ end
81
+
82
+ context "save" do
83
+
84
+ should "require password" do
85
+ assert_raise(MissingParameter) do
86
+ @note.save(nil)
87
+ end
88
+ end
89
+
90
+ context "with password" do
91
+ setup do
92
+ @password = '12345'
93
+ Crypt::Blowfish.any_instance.expects(:encrypt_string).with(@note.data).returns('ENCRYPTED DATA')
94
+ @note.save(@password)
95
+ end
96
+
97
+ should "encrypt data and place in @encrypted" do
98
+ assert_equal 'ENCRYPTED DATA', @note.encrypted
99
+ end
100
+
101
+ should "write to file in path with #name" do
102
+ assert File.readable?(@note.file_path)
103
+ assert_equal @note.encrypted, File.read(@note.file_path)
104
+ end
105
+
106
+ # teardown do
107
+ # File.unlink(purse_path, 'sander')
108
+ # end
109
+ end
110
+ end
111
+
112
+ context "encrypt" do
113
+ # blowfish = Crypt::Blowfish.new("A key up to 56 bytes long")
114
+ # plainBlock = "ABCD1234"
115
+ # encryptedBlock = blowfish.encrypt_block(plainBlock)
116
+ # decryptedBlock = blowfish.decrypt_block(encryptedBlock)
117
+
118
+ should "require password" do
119
+ assert_raise(MissingParameter) do
120
+ @note.encrypt(nil)
121
+ end
122
+ end
123
+
124
+ context "with password" do
125
+ setup do
126
+ @password = 'Test123'
127
+ Crypt::Blowfish.any_instance.expects(:encrypt_string).with(@note.data).returns('ENCRYPTED DATA')
128
+ @note.encrypt(@password)
129
+ end
130
+
131
+ should "save encrypted data to encrypted" do
132
+ assert_equal 'ENCRYPTED DATA', @note.encrypted
133
+ end
134
+ end
135
+ end
136
+
137
+ context "decrypt" do
138
+ setup do
139
+ @note = Note.new(purse_path, 'sander', 'ENCRYPTED DATA', :encrypted => true)
140
+ end
141
+
142
+ should "require password" do
143
+ assert_raise(MissingParameter) do
144
+ @note.decrypt(nil)
145
+ end
146
+ end
147
+
148
+ context "with password" do
149
+ setup do
150
+ @password = 'Test123'
151
+ Crypt::Blowfish.any_instance.expects(:decrypt_string).with(@note.encrypted).returns('Nonsense')
152
+ @note.decrypt(@password)
153
+ end
154
+
155
+ should "save decrypted data to @data" do
156
+ assert_equal 'Nonsense', @note.data
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ context "on the class" do
163
+ context "load" do
164
+
165
+ should "require path" do
166
+ assert_raise(MissingParameter) do
167
+ Note.load(nil, 'sander')
168
+ end
169
+ end
170
+
171
+ should "name" do
172
+ assert_raise(MissingParameter) do
173
+ Note.load(nil, 'sander')
174
+ end
175
+ end
176
+
177
+ should "raise error if file can not be found" do
178
+ assert_raise(MissingFile) do
179
+ Note.load(purse_path, "file_#{rand(5)}")
180
+ end
181
+ end
182
+
183
+ context "with a saved encrypted file" do
184
+ setup do
185
+ # Crypt::Blowfish.any_instance.expects(:decrypt_block).with('ENCRYPTED DATA').returns('Nonsense')
186
+ @note = Note.load(purse_path, 'sander')
187
+ end
188
+
189
+ should "return Note" do
190
+ assert @note.is_a?(Note)
191
+ end
192
+
193
+ should "set @encrypted" do
194
+ assert_equal 'ENCRYPTED DATA', @note.encrypted
195
+ end
196
+
197
+ should "not set @data" do
198
+ assert_nil @note.data
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ end