carps 0.2.1

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.
Files changed (157) hide show
  1. data/COPYING +674 -0
  2. data/GEM_DESCRIPTION +10 -0
  3. data/History.txt +4 -0
  4. data/Manifest.txt +156 -0
  5. data/PostInstall.txt +20 -0
  6. data/README.rdoc +141 -0
  7. data/Rakefile +28 -0
  8. data/bin/carps +123 -0
  9. data/bin/carps_init +29 -0
  10. data/bin/carps_ipc_test +44 -0
  11. data/bin/carps_mod_saver_test +71 -0
  12. data/bin/carps_mod_test +62 -0
  13. data/config/website.yml +2 -0
  14. data/features/character_sheet.feature +40 -0
  15. data/features/crash.feature +15 -0
  16. data/features/crypt.feature +22 -0
  17. data/features/dice.feature +173 -0
  18. data/features/dm.feature +36 -0
  19. data/features/dmll.feature +51 -0
  20. data/features/edit.feature +10 -0
  21. data/features/email.feature +29 -0
  22. data/features/interface.feature +17 -0
  23. data/features/ipc.feature +10 -0
  24. data/features/mailbox.feature +33 -0
  25. data/features/mod.feature +31 -0
  26. data/features/parser.feature +9 -0
  27. data/features/persistent_protocol.feature +14 -0
  28. data/features/player.feature +22 -0
  29. data/features/player_turn.feature +29 -0
  30. data/features/random.feature +15 -0
  31. data/features/rule.feature +19 -0
  32. data/features/safety.feature +13 -0
  33. data/features/sessions.feature +16 -0
  34. data/features/start_dm.feature +18 -0
  35. data/features/start_player.feature +8 -0
  36. data/features/step_definitions/common_steps.rb +170 -0
  37. data/features/steps/character_sheet.rb +89 -0
  38. data/features/steps/crash.rb +27 -0
  39. data/features/steps/crypt.rb +166 -0
  40. data/features/steps/dice.rb +91 -0
  41. data/features/steps/dm.rb +147 -0
  42. data/features/steps/dmll.rb +47 -0
  43. data/features/steps/edit.rb +7 -0
  44. data/features/steps/email.rb +108 -0
  45. data/features/steps/general.rb +5 -0
  46. data/features/steps/interface.rb +64 -0
  47. data/features/steps/ipc.rb +22 -0
  48. data/features/steps/mailbox.rb +126 -0
  49. data/features/steps/mod.rb +25 -0
  50. data/features/steps/parser.rb +23 -0
  51. data/features/steps/persistent_protocol.rb +29 -0
  52. data/features/steps/player.rb +82 -0
  53. data/features/steps/player_turn.rb +56 -0
  54. data/features/steps/random.rb +47 -0
  55. data/features/steps/rule.rb +53 -0
  56. data/features/steps/safety.rb +17 -0
  57. data/features/steps/sessions.rb +37 -0
  58. data/features/steps/start_dm.rb +46 -0
  59. data/features/steps/start_player.rb +65 -0
  60. data/features/steps/timeout.rb +32 -0
  61. data/features/steps/type_verification.rb +36 -0
  62. data/features/steps/wizard.rb +123 -0
  63. data/features/support/common.rb +29 -0
  64. data/features/support/env.rb +14 -0
  65. data/features/support/matchers.rb +11 -0
  66. data/features/timeout.feature +11 -0
  67. data/features/type_verification.feature +48 -0
  68. data/features/wizard.feature +50 -0
  69. data/lib/carps/crypt/accept_handshake.rb +40 -0
  70. data/lib/carps/crypt/default_messages.rb +29 -0
  71. data/lib/carps/crypt/handshake.rb +41 -0
  72. data/lib/carps/crypt/mailbox.rb +265 -0
  73. data/lib/carps/crypt/mailer.rb +220 -0
  74. data/lib/carps/crypt/peer.rb +123 -0
  75. data/lib/carps/crypt/public_key.rb +60 -0
  76. data/lib/carps/crypt.rb +23 -0
  77. data/lib/carps/email/config.rb +122 -0
  78. data/lib/carps/email/imap.rb +156 -0
  79. data/lib/carps/email/smtp.rb +119 -0
  80. data/lib/carps/email/string.rb +30 -0
  81. data/lib/carps/email.rb +21 -0
  82. data/lib/carps/mod/action.rb +36 -0
  83. data/lib/carps/mod/answers.rb +76 -0
  84. data/lib/carps/mod/client_turn.rb +88 -0
  85. data/lib/carps/mod/dice.rb +360 -0
  86. data/lib/carps/mod/dm/interface.rb +160 -0
  87. data/lib/carps/mod/dm/mod.rb +409 -0
  88. data/lib/carps/mod/dm/reporter.rb +112 -0
  89. data/lib/carps/mod/dm/resource.rb +88 -0
  90. data/lib/carps/mod/dm/room.rb +33 -0
  91. data/lib/carps/mod/interface.rb +73 -0
  92. data/lib/carps/mod/launch.rb +108 -0
  93. data/lib/carps/mod/mod.rb +52 -0
  94. data/lib/carps/mod/player/interface.rb +76 -0
  95. data/lib/carps/mod/player/mod.rb +109 -0
  96. data/lib/carps/mod/question.rb +63 -0
  97. data/lib/carps/mod/rule.rb +112 -0
  98. data/lib/carps/mod/sheet/character.rb +82 -0
  99. data/lib/carps/mod/sheet/editor.rb +97 -0
  100. data/lib/carps/mod/sheet/new_sheet.rb +71 -0
  101. data/lib/carps/mod/sheet/schema.rb +84 -0
  102. data/lib/carps/mod/sheet/type.rb +161 -0
  103. data/lib/carps/mod/sheet/verifier.rb +41 -0
  104. data/lib/carps/mod/status_report.rb +51 -0
  105. data/lib/carps/mod.rb +40 -0
  106. data/lib/carps/protocol/keyword.rb +104 -0
  107. data/lib/carps/protocol/message.rb +138 -0
  108. data/lib/carps/protocol.rb +19 -0
  109. data/lib/carps/service/client_parser.rb +34 -0
  110. data/lib/carps/service/dm/config.rb +76 -0
  111. data/lib/carps/service/dm/mailer.rb +70 -0
  112. data/lib/carps/service/dm/new_game.rb +101 -0
  113. data/lib/carps/service/dm/start.rb +47 -0
  114. data/lib/carps/service/game.rb +101 -0
  115. data/lib/carps/service/interface.rb +174 -0
  116. data/lib/carps/service/invite.rb +79 -0
  117. data/lib/carps/service/mod.rb +43 -0
  118. data/lib/carps/service/player/config.rb +78 -0
  119. data/lib/carps/service/player/mailer.rb +49 -0
  120. data/lib/carps/service/player/start.rb +60 -0
  121. data/lib/carps/service/server_parser.rb +33 -0
  122. data/lib/carps/service/session.rb +96 -0
  123. data/lib/carps/service/start/config.rb +71 -0
  124. data/lib/carps/service/start/interface.rb +101 -0
  125. data/lib/carps/service/start/mailer.rb +46 -0
  126. data/lib/carps/service.rb +35 -0
  127. data/lib/carps/test.rb +34 -0
  128. data/lib/carps/ui/colour.rb +28 -0
  129. data/lib/carps/ui/error.rb +39 -0
  130. data/lib/carps/ui/highlight.rb +32 -0
  131. data/lib/carps/ui/question.rb +63 -0
  132. data/lib/carps/ui/warn.rb +37 -0
  133. data/lib/carps/ui.rb +21 -0
  134. data/lib/carps/util/config.rb +162 -0
  135. data/lib/carps/util/editor.rb +147 -0
  136. data/lib/carps/util/error.rb +75 -0
  137. data/lib/carps/util/files.rb +48 -0
  138. data/lib/carps/util/init.rb +93 -0
  139. data/lib/carps/util/process.rb +150 -0
  140. data/lib/carps/util/timeout.rb +31 -0
  141. data/lib/carps/util/windows.rb +29 -0
  142. data/lib/carps/util.rb +24 -0
  143. data/lib/carps/wizard/dm.rb +41 -0
  144. data/lib/carps/wizard/player.rb +40 -0
  145. data/lib/carps/wizard/steps.rb +494 -0
  146. data/lib/carps/wizard/wizard.rb +126 -0
  147. data/lib/carps/wizard.rb +21 -0
  148. data/lib/carps.rb +45 -0
  149. data/permission +16 -0
  150. data/script/console +10 -0
  151. data/script/destroy +14 -0
  152. data/script/generate +14 -0
  153. data/tasks/readme_site.rake +28 -0
  154. data/test/test_carps.rb +11 -0
  155. data/test/test_helper.rb +3 -0
  156. data/website/index.html +271 -0
  157. metadata +304 -0
@@ -0,0 +1,265 @@
1
+ # Copyright 2010 John Morrice
2
+
3
+ # This file is part of CARPS.
4
+
5
+ # CARPS is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # CARPS is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with CARPS. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ # This mailbox receives all messages that come in
19
+
20
+ require "carps/ui/warn"
21
+
22
+ require "carps/util/process"
23
+ require "carps/util/files"
24
+
25
+ require "drb"
26
+
27
+ module CARPS
28
+
29
+ # The mailbox's responsibility is in sending messages and securely and robustly receiving them
30
+ #
31
+ # It has knowledge is of the public keys of the Mailer s of the remote peers
32
+ class Mailbox
33
+
34
+ include DRbUndumped
35
+
36
+ # Create the mailbox from a simple, synchronous mail sender and receiver.
37
+ #
38
+ # The third parameter is a MessageParser.
39
+ #
40
+ # The fourth parameter is a SessionManager.
41
+ def initialize sender, receiver, parser, manager
42
+ @manager = manager
43
+ @receiver = receiver
44
+ @parser = parser
45
+ @sender = sender
46
+ @mail = []
47
+ @peers = {}
48
+ @secure = false
49
+ # Semaphore to make sure only one thread can send mail at any one time
50
+ @ssemaphore = Mutex.new
51
+ # Semaphore to make sure only one thread can receive mail at any one time
52
+ @rsemaphore = Mutex.new
53
+ # Load mails from the last session
54
+ load_old_mails
55
+ # Receive mail
56
+ receive_forever
57
+ end
58
+
59
+ # Shutdown the mailbox
60
+ def shutdown
61
+ @child.kill
62
+ end
63
+
64
+ # Add a new peer
65
+ def add_peer peer
66
+ @peers[peer.addr] = peer
67
+ end
68
+
69
+ # Is this already a peer?
70
+ def peer? peer
71
+ @peers.member? peer
72
+ end
73
+
74
+ # Send a message
75
+ def send to, message
76
+ @ssemaphore.synchronize do
77
+ @sender.send to, message
78
+ end
79
+ end
80
+
81
+ # Tag some text
82
+ def tag text
83
+ @manager.tag text
84
+ end
85
+
86
+ # Securely read a message. Block until one occurs.
87
+ def read type, must_be_from=nil
88
+ msg = nil
89
+ until msg
90
+ msg = search type, must_be_from
91
+ sleep 1
92
+ end
93
+ # Ding!
94
+ puts "\a"
95
+ return msg
96
+ end
97
+
98
+ # Check for a new message. Don't block
99
+ def check type, must_be_from=nil
100
+ search type, must_be_from
101
+ end
102
+
103
+ # Insecurely read a message. Block until one comes.
104
+ def insecure_read type, must_be_from=nil
105
+ msg = nil
106
+ until msg
107
+ msg = insecure_search type, must_be_from
108
+ sleep 1
109
+ end
110
+ # Ding!
111
+ puts "\a"
112
+ return msg
113
+ end
114
+
115
+ # Check for new messages insecurely. Don't block.
116
+ def insecure_check type, must_be_from=nil
117
+ insecure_search type, must_be_from
118
+ end
119
+
120
+ private
121
+
122
+ # See if there is an appropriate message in the mail box
123
+ def search type, must_be_from
124
+ @rsemaphore.synchronize do
125
+ @mail.each_index do |index|
126
+ mail = @mail[index]
127
+ from = mail.from
128
+ if secure from
129
+ unless @peers[from].verify mail
130
+ remove_mail index
131
+ next
132
+ end
133
+ end
134
+ pass = appropriate?(mail, type, must_be_from)
135
+ if pass
136
+ remove_mail index
137
+ return mail
138
+ end
139
+ end
140
+ nil
141
+ end
142
+ end
143
+
144
+ # Was the mail message appropriate?
145
+ def appropriate? mail, type, must_be_from
146
+ pass = mail.class == type
147
+ if must_be_from
148
+ pass = pass and mail.from == must_be_from
149
+ end
150
+ pass and @manager.belong? mail
151
+ end
152
+
153
+ # Remove a mail message
154
+ def remove_mail index
155
+ @mail[index].delete
156
+ @mail.delete_at index
157
+ end
158
+
159
+ # Communication with someone is secure if there is a peer for them
160
+ def secure addr
161
+ @peers.member? addr
162
+ end
163
+
164
+ # Insecurely see if there is an appropriate message in the mail box
165
+ def insecure_search type, must_be_from
166
+ @rsemaphore.synchronize do
167
+ @mail.each_index do |index|
168
+ mail = @mail[index]
169
+ pass = appropriate?(mail, type, must_be_from)
170
+ if pass
171
+ remove_mail index
172
+ return mail
173
+ end
174
+ end
175
+ nil
176
+ end
177
+ end
178
+
179
+ # Receive new mail
180
+ def receive_forever
181
+ @child = Thread.fork do
182
+ loop do
183
+ receive_new
184
+ sleep 1
185
+ end
186
+ end
187
+ end
188
+
189
+ # Read new mail messages into the mail box
190
+ def receive_new
191
+ mail = @receiver.read
192
+ mail.each do |blob|
193
+ decode_mail blob
194
+ end
195
+ end
196
+
197
+ # Read a new mail message from a blob of text
198
+ def decode_mail blob, persistence = {:save_mail => true}
199
+ input = blob
200
+ who = nil
201
+
202
+ begin
203
+ # Find who sent the message
204
+ who, blob = find K.addr, blob
205
+ rescue Expected
206
+ UI::warn "Mail message did not contain sender.", blob
207
+ return
208
+ end
209
+
210
+ # Get the security information from the mail
211
+ delayed_crypt, blob = security_info blob
212
+
213
+ # Find the message's session
214
+ session = nil
215
+ begin
216
+ session, blob = find K.session, blob
217
+ rescue Expected
218
+ UI::warn "Mail message did not contain session.", blob
219
+ return
220
+ end
221
+
222
+ # Parse a message
223
+ msg = @parser.parse blob
224
+
225
+ if msg
226
+ msg.session = session
227
+ msg.crypt = delayed_crypt
228
+ msg.from = who
229
+ puts "Mail from #{who}: #{msg.class.to_s}"
230
+ # Save the text we parsed the message from.
231
+ if persistence[:save_mail]
232
+ msg.save input
233
+ end
234
+ path = persistence[:path]
235
+ if path
236
+ msg.path = path
237
+ end
238
+ @rsemaphore.synchronize do
239
+ @mail.push msg
240
+ end
241
+ else
242
+ UI::warn "Failed to parse message from #{who}"
243
+ end
244
+ end
245
+
246
+ # Load mails from the last session
247
+ def load_old_mails
248
+ old_mails = files $CONFIG + "/.mail"
249
+ old_mails.each do |fn|
250
+ blob = nil
251
+ begin
252
+ blob = File.read fn
253
+ rescue StandardError => e
254
+ UI::put_error "Could not read old message: #{e}"
255
+ end
256
+ if blob
257
+ blob.force_encoding "ASCII-8BIT"
258
+ decode_mail blob, {:save_mail => false, :path => fn}
259
+ end
260
+ end
261
+ end
262
+
263
+ end
264
+
265
+ end
@@ -0,0 +1,220 @@
1
+ # Copyright 2010 John Morrice
2
+
3
+ # This file is part of CARPS.
4
+
5
+ # CARPS is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # CARPS is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with CARPS. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+
19
+ require "carps/protocol/keyword"
20
+
21
+ require "carps/ui/warn"
22
+ require "carps/ui/question"
23
+
24
+ require "carps/util/process"
25
+ require "carps/util/files"
26
+
27
+ require "carps/crypt/handshake"
28
+ require "carps/crypt/public_key"
29
+ require "carps/crypt/accept_handshake"
30
+ require "carps/crypt/peer"
31
+
32
+ require "digest/md5"
33
+
34
+ require "openssl"
35
+
36
+ module CARPS
37
+
38
+ # High level CARPS mail client supporting strong cryptographic message signing.
39
+ #
40
+ # It has knowledge of our own public and private key. Its big responsibility is turning Messages into Strings and signing them.
41
+ class Mailer
42
+
43
+ # Extend protocol for sharing our address
44
+ protoval :addr
45
+
46
+ # The first parameter is the email address
47
+ #
48
+ # The second the Mailbox.
49
+ def initialize address, mailbox
50
+ @addr = address
51
+ @mailbox = mailbox
52
+ @private_key = get_keys
53
+ @public_key = @private_key.public_key
54
+ # Load the old peers
55
+ load_peers
56
+ end
57
+
58
+ # Perform a handshake to authenticate with a peer
59
+ def handshake to
60
+ if @mailbox.peer? to
61
+ puts "No need for handshake: " + to + " is already a known peer."
62
+ else
63
+ puts "Offering cryptographic handshake to #{to}"
64
+ # Create a new peer
65
+ peer = Peer.new to
66
+ @mailbox.add_peer peer
67
+ # Request a handshake
68
+ send to, Handshake.new
69
+ # Get the peer's key
70
+ their_key = @mailbox.insecure_read PublicKey, to
71
+ peer.your_key their_key.key
72
+ peer.save
73
+ # Send our key
74
+ send to, PublicKey.new(@public_key)
75
+ # Receive an okay message
76
+ read AcceptHandshake, to
77
+ puts "Established spoof-proof communications with #{to}"
78
+ end
79
+ end
80
+
81
+ # Shutdown the mailer
82
+ def shutdown
83
+ @mailbox.shutdown
84
+ end
85
+
86
+ # Check for handshakes
87
+ def check_handshake
88
+ @mailbox.insecure_check Handshake
89
+ end
90
+
91
+ # Respond to a handshake request
92
+ def handle_handshake handshake
93
+ # Get the peer's address
94
+ from = handshake.from
95
+ puts "Receiving handshake request from #{from}."
96
+ if @mailbox.peer? from
97
+ UI::warn "Handshake request from #{from} has been dropped because #{from} is already a known peer", "Possible spoofing attack."
98
+ else
99
+ # See if the user accepts the handshake.
100
+ accept = accept_handshake? from
101
+ if accept
102
+ # Send our key to the peer
103
+ send from, PublicKey.new(@public_key)
104
+ # Get their key
105
+ peer_key = @mailbox.insecure_read PublicKey, from
106
+ # Create a new peer
107
+ peer = Peer.new from
108
+ @mailbox.add_peer peer
109
+ peer.your_key peer_key.key
110
+ peer.save
111
+ # Send an okay message
112
+ send from, AcceptHandshake.new
113
+ puts "Established spoof-proof communications with #{from}."
114
+ end
115
+ end
116
+ end
117
+
118
+ # Give our address to interested parties
119
+ def address
120
+ @addr
121
+ end
122
+
123
+ # Send a message
124
+ def send to, message
125
+ text = message.emit
126
+ # The mailbox tags the message with a session key
127
+ text = @mailbox.tag text
128
+ # Sign the message
129
+ digest = Digest::MD5.digest text
130
+ sig = @private_key.syssign digest
131
+ mail = (V.addr @addr) + (V.sig sig) + text + K.end
132
+ @mailbox.send to, mail
133
+ puts "#{message.class} sent to " + to
134
+ end
135
+
136
+ # Receive a message. Block until it is here.
137
+ def read type, must_be_from=nil
138
+ @mailbox.read type, must_be_from
139
+ end
140
+
141
+ # Check for a message. Don't block! Return nil if nothing is available.
142
+ def check type, must_be_from=nil
143
+ @mailbox.check type, must_be_from
144
+ end
145
+
146
+ protected
147
+
148
+ # Ask the user if they accept the handshake.
149
+ #
150
+ # Refactored out for tinkering and automated testing.
151
+ def accept_handshake? from
152
+ UI::confirm "Accept handshake from #{from}?"
153
+ end
154
+
155
+
156
+ private
157
+
158
+ # Get cryptographic keys
159
+ #
160
+ # If we can't find them, regenerate them
161
+ def get_keys
162
+ pkey = OpenSSL::PKey
163
+ if File.exists? keyfile
164
+ begin
165
+ pem = File.read keyfile
166
+ return pkey::DSA.new pem
167
+ rescue
168
+ end
169
+ end
170
+ UI::warn "Could not read cryptographic key from #{keyfile}"
171
+ return keygen
172
+ end
173
+
174
+ # The key file
175
+ def keyfile
176
+ keyfile = $CONFIG + ".key"
177
+ end
178
+
179
+ # Generate keys
180
+ def keygen
181
+ puts "Generating cryptographic keys. This may take a minute."
182
+ key = OpenSSL::PKey::DSA.generate 2048
183
+ begin
184
+ pri = File.new keyfile, "w"
185
+ pri.chmod 0600
186
+ pri.write key.to_pem
187
+ pri.close
188
+ rescue
189
+ UI::warn "Could not save cryptographic keys in #{keyfile}", "They will be regenerated next time CARPS is run."
190
+ end
191
+ key
192
+ end
193
+
194
+
195
+ # Peer directory
196
+ def peer_dir
197
+ # Yes, this is strange. It's to cope with needed to have two mailers at once for testing, which never would normally happen.
198
+ # In other words, global variables are bad and Haskell is right.
199
+ unless @peer_dir
200
+ @peer_dir = $CONFIG + "/.peers/"
201
+ end
202
+ @peer_dir
203
+ end
204
+
205
+ # Load previous peers
206
+ def load_peers
207
+ peer_file_names = files peer_dir
208
+ peer_file_names.each do |p|
209
+ load_peer p
210
+ end
211
+ end
212
+
213
+ # Load a peer
214
+ def load_peer peer_file_name
215
+ peer = Peer.load ".peers/" + File.basename(peer_file_name)
216
+ @mailbox.add_peer peer
217
+ end
218
+
219
+ end
220
+ end
@@ -0,0 +1,123 @@
1
+ # Copyright 2010 John Morrice
2
+
3
+ # This file is part of CARPS.
4
+
5
+ # CARPS is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # CARPS is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with CARPS. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require "carps/util"
19
+
20
+ require "carps/ui"
21
+
22
+ require "carps/protocol/keyword"
23
+
24
+ require "openssl"
25
+
26
+ require "yaml"
27
+
28
+ module CARPS
29
+
30
+ # Clean the end of an email
31
+ #
32
+ # Strip the last end marker and any text after it
33
+ def clean_end blob
34
+ rb = blob.reverse
35
+ before, after = rb.split K.end.reverse, 2
36
+ if after
37
+ return after.reverse
38
+ end
39
+ nil
40
+ end
41
+
42
+ # Fetch security information from an email
43
+ def security_info blob
44
+ blob = clean_end blob
45
+ sig = nil
46
+ begin
47
+ sig, blob = find K.sig, blob
48
+ rescue
49
+ UI::warn "Message signature was malformed", blob
50
+ return nil
51
+ end
52
+ # If the digest is the hash of the message and the signature matches the digest then all is well
53
+ dig = Digest::MD5.digest blob
54
+ [[sig, dig], blob]
55
+ end
56
+
57
+ # Peers
58
+ class Peer < UserConfig
59
+
60
+ # Extend protocol for signed data
61
+ protoval :sig
62
+
63
+ # Create a new peer
64
+ def initialize addr
65
+ @addr = addr
66
+ end
67
+
68
+ def addr
69
+ @addr
70
+ end
71
+
72
+ # Tell this peer its key
73
+ def your_key key
74
+ @peer_key = key
75
+ end
76
+
77
+ # Perform a verification on an email
78
+ def verify mail
79
+ sig, dig = mail.crypt
80
+ begin
81
+ pass = @peer_key.sysverify dig, sig
82
+ rescue OpenSSL::PKey::DSAError => e
83
+ UI::warn "Someone sent you an invalid signature: #{e.message}"
84
+ return false
85
+ end
86
+ if pass
87
+ return true
88
+ else
89
+ UI::warn "Someone has attempted to spoof an email from #{mail.from}", mail.to_s
90
+ return false
91
+ end
92
+ end
93
+
94
+ # Save as YAML file in .peers
95
+ def save
96
+ y = emit.to_yaml
97
+ begin
98
+ write_file_in ".peers/", y
99
+ rescue StandardError => e
100
+ UI::warn "Could not save Peer in .peers/"
101
+ end
102
+ end
103
+
104
+ protected
105
+
106
+ # Emit this peer as a yaml document
107
+ def emit
108
+ {"addr" => @addr, "key" => @peer_key.to_pem}
109
+ end
110
+
111
+ def parse_yaml conf
112
+ key_pem = read_conf conf, "key"
113
+ @addr = read_conf conf, "addr"
114
+ [key_pem]
115
+ end
116
+
117
+ def load_resources key_pem
118
+ @peer_key = OpenSSL::PKey::DSA.new key_pem
119
+ end
120
+
121
+ end
122
+
123
+ end
@@ -0,0 +1,60 @@
1
+ # Copyright 2010 John Morrice
2
+
3
+ # This file is part of CARPS.
4
+
5
+ # CARPS is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # CARPS is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with CARPS. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require "carps/protocol/message"
19
+ require "carps/protocol/keyword"
20
+
21
+ require "openssl"
22
+
23
+ module CARPS
24
+
25
+ # Transmit public keys over email
26
+ class PublicKey < Message
27
+
28
+ # Extend the protocol for public_keys
29
+ protoval "key"
30
+
31
+ # Create a new handshake
32
+ def initialize public_key
33
+ @public_key = public_key
34
+ end
35
+
36
+ # Parse from text
37
+ def PublicKey.parse blob
38
+ key, blob = find K.key, blob
39
+ pkey = OpenSSL::PKey
40
+ begin
41
+ key = pkey::DSA.new key
42
+ return [PublicKey.new(key), blob]
43
+ rescue pkey::DSAError
44
+ raise Expected, "Public key"
45
+ end
46
+ end
47
+
48
+ # Emit the handshake as text
49
+ def emit
50
+ V.key @public_key.to_pem
51
+ end
52
+
53
+ # Share the public key
54
+ def key
55
+ @public_key
56
+ end
57
+
58
+ end
59
+
60
+ end
@@ -0,0 +1,23 @@
1
+ # Copyright 2010 John Morrice
2
+
3
+ # This file is part of CARPS.
4
+
5
+ # CARPS is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # CARPS is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with CARPS. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require "carps/crypt/accept_handshake"
19
+ require "carps/crypt/default_messages"
20
+ require "carps/crypt/handshake"
21
+ require "carps/crypt/mailbox"
22
+ require "carps/crypt/mailer"
23
+ require "carps/crypt/public_key"