meshchat 0.8.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +39 -11
  3. data/lib/meshchat.rb +48 -42
  4. data/lib/meshchat/configuration.rb +14 -0
  5. data/lib/meshchat/configuration/app_config.rb +63 -0
  6. data/lib/meshchat/configuration/database.rb +41 -0
  7. data/lib/meshchat/{config → configuration}/hash_file.rb +7 -6
  8. data/lib/meshchat/configuration/identity.rb +79 -0
  9. data/lib/meshchat/{config → configuration}/settings.rb +22 -26
  10. data/lib/meshchat/debug.rb +69 -0
  11. data/lib/meshchat/encryption.rb +7 -2
  12. data/lib/meshchat/encryption/aes_rsa.rb +2 -1
  13. data/lib/meshchat/encryption/passthrough.rb +5 -3
  14. data/lib/meshchat/locale/en.yml +14 -0
  15. data/lib/meshchat/models/node.rb +140 -0
  16. data/lib/meshchat/network.rb +19 -0
  17. data/lib/meshchat/network/dispatcher.rb +83 -0
  18. data/lib/meshchat/network/errors.rb +11 -0
  19. data/lib/meshchat/network/incoming.rb +13 -0
  20. data/lib/meshchat/network/incoming/message_decryptor.rb +51 -0
  21. data/lib/meshchat/network/incoming/message_processor.rb +75 -0
  22. data/lib/meshchat/network/incoming/request_processor.rb +30 -0
  23. data/lib/meshchat/network/local.rb +12 -0
  24. data/lib/meshchat/network/local/connection.rb +58 -0
  25. data/lib/meshchat/network/local/server.rb +69 -0
  26. data/lib/meshchat/network/message.rb +34 -0
  27. data/lib/meshchat/network/message/base.rb +139 -0
  28. data/lib/meshchat/network/message/chat.rb +9 -0
  29. data/lib/meshchat/network/message/disconnect.rb +21 -0
  30. data/lib/meshchat/network/message/emote.rb +9 -0
  31. data/lib/meshchat/network/message/factory.rb +80 -0
  32. data/lib/meshchat/network/message/node_list.rb +75 -0
  33. data/lib/meshchat/network/message/node_list_diff.rb +18 -0
  34. data/lib/meshchat/network/message/node_list_hash.rb +32 -0
  35. data/lib/meshchat/network/message/ping.rb +31 -0
  36. data/lib/meshchat/network/message/ping_reply.rb +12 -0
  37. data/lib/meshchat/network/message/whisper.rb +28 -0
  38. data/lib/meshchat/network/remote.rb +13 -0
  39. data/lib/meshchat/network/remote/connection.rb +28 -0
  40. data/lib/meshchat/network/remote/relay.rb +109 -0
  41. data/lib/meshchat/network/remote/relay_pool.rb +52 -0
  42. data/lib/meshchat/ui.rb +13 -0
  43. data/lib/meshchat/ui/cli.rb +48 -0
  44. data/lib/meshchat/ui/cli/base.rb +39 -0
  45. data/lib/meshchat/ui/cli/input_factory.rb +50 -0
  46. data/lib/meshchat/ui/cli/keyboard_line_input.rb +14 -0
  47. data/lib/meshchat/ui/command.rb +51 -0
  48. data/lib/meshchat/ui/command/base.rb +77 -0
  49. data/lib/meshchat/ui/command/bind.rb +47 -0
  50. data/lib/meshchat/ui/command/chat.rb +31 -0
  51. data/lib/meshchat/ui/command/config.rb +37 -0
  52. data/lib/meshchat/ui/command/emote.rb +23 -0
  53. data/lib/meshchat/ui/command/exit.rb +16 -0
  54. data/lib/meshchat/ui/command/help.rb +20 -0
  55. data/lib/meshchat/ui/command/identity.rb +16 -0
  56. data/lib/meshchat/ui/command/import.rb +42 -0
  57. data/lib/meshchat/ui/command/irb.rb +22 -0
  58. data/lib/meshchat/ui/command/offline.rb +23 -0
  59. data/lib/meshchat/ui/command/online.rb +18 -0
  60. data/lib/meshchat/ui/command/ping.rb +65 -0
  61. data/lib/meshchat/ui/command/ping_all.rb +19 -0
  62. data/lib/meshchat/ui/command/send_disconnect.rb +20 -0
  63. data/lib/meshchat/ui/command/server.rb +22 -0
  64. data/lib/meshchat/ui/command/share.rb +16 -0
  65. data/lib/meshchat/ui/command/whisper.rb +40 -0
  66. data/lib/meshchat/ui/display.rb +78 -0
  67. data/lib/meshchat/ui/display/base.rb +58 -0
  68. data/lib/meshchat/ui/display/manager.rb +59 -0
  69. data/lib/meshchat/ui/notifier.rb +9 -0
  70. data/lib/meshchat/ui/notifier/base.rb +33 -0
  71. data/lib/meshchat/version.rb +3 -2
  72. metadata +150 -80
  73. data/lib/meshchat/cli.rb +0 -188
  74. data/lib/meshchat/cli/base.rb +0 -13
  75. data/lib/meshchat/cli/input.rb +0 -37
  76. data/lib/meshchat/command/base.rb +0 -80
  77. data/lib/meshchat/command/bind.rb +0 -44
  78. data/lib/meshchat/command/chat.rb +0 -30
  79. data/lib/meshchat/command/config.rb +0 -34
  80. data/lib/meshchat/command/emote.rb +0 -20
  81. data/lib/meshchat/command/exit.rb +0 -13
  82. data/lib/meshchat/command/help.rb +0 -17
  83. data/lib/meshchat/command/identity.rb +0 -13
  84. data/lib/meshchat/command/import.rb +0 -41
  85. data/lib/meshchat/command/init.rb +0 -34
  86. data/lib/meshchat/command/irb.rb +0 -23
  87. data/lib/meshchat/command/listen.rb +0 -13
  88. data/lib/meshchat/command/offline.rb +0 -20
  89. data/lib/meshchat/command/online.rb +0 -15
  90. data/lib/meshchat/command/ping.rb +0 -65
  91. data/lib/meshchat/command/ping_all.rb +0 -15
  92. data/lib/meshchat/command/send_disconnect.rb +0 -15
  93. data/lib/meshchat/command/server.rb +0 -20
  94. data/lib/meshchat/command/share.rb +0 -13
  95. data/lib/meshchat/command/stop_listening.rb +0 -13
  96. data/lib/meshchat/command/whisper.rb +0 -38
  97. data/lib/meshchat/database.rb +0 -30
  98. data/lib/meshchat/display.rb +0 -33
  99. data/lib/meshchat/display/base.rb +0 -60
  100. data/lib/meshchat/display/manager.rb +0 -55
  101. data/lib/meshchat/instance.rb +0 -40
  102. data/lib/meshchat/message.rb +0 -41
  103. data/lib/meshchat/message/base.rb +0 -97
  104. data/lib/meshchat/message/chat.rb +0 -19
  105. data/lib/meshchat/message/disconnect.rb +0 -13
  106. data/lib/meshchat/message/emote.rb +0 -9
  107. data/lib/meshchat/message/node_list.rb +0 -63
  108. data/lib/meshchat/message/node_list_diff.rb +0 -15
  109. data/lib/meshchat/message/node_list_hash.rb +0 -33
  110. data/lib/meshchat/message/ping.rb +0 -32
  111. data/lib/meshchat/message/ping_reply.rb +0 -9
  112. data/lib/meshchat/message/relay.rb +0 -43
  113. data/lib/meshchat/message/whisper.rb +0 -36
  114. data/lib/meshchat/models/entry.rb +0 -104
  115. data/lib/meshchat/net/client.rb +0 -83
  116. data/lib/meshchat/net/listener/errors.rb +0 -11
  117. data/lib/meshchat/net/listener/request.rb +0 -48
  118. data/lib/meshchat/net/listener/request_processor.rb +0 -50
  119. data/lib/meshchat/net/listener/server.rb +0 -114
  120. data/lib/meshchat/net/request.rb +0 -29
  121. data/lib/meshchat/notifier/base.rb +0 -31
@@ -1,32 +0,0 @@
1
- module MeshChat
2
- module Message
3
- class Ping < Base
4
-
5
- def display
6
- # we'll never display our own ping to someone else...
7
- # or shouldn't.... or there should be different output
8
- # TODO: display is a bad method name
9
- name = payload['sender']['alias']
10
- location = payload['sender']['location']
11
-
12
- "#{name}@#{location} pinged you."
13
- end
14
-
15
- def handle
16
- respond
17
- display
18
- end
19
-
20
- def respond
21
- location = payload['sender']['location']
22
-
23
- node = Node.find_by_location(location)
24
-
25
- MeshChat::Net::Client.send(
26
- node: node,
27
- message: PingReply.new
28
- )
29
- end
30
- end
31
- end
32
- end
@@ -1,9 +0,0 @@
1
- module MeshChat
2
- module Message
3
- class PingReply < Base
4
- def display
5
- 'ping successful'.freeze if Settings.debug?
6
- end
7
- end
8
- end
9
- end
@@ -1,43 +0,0 @@
1
- module MeshChat
2
- module Message
3
- class Relay < Base
4
- def initialize(
5
- message: nil,
6
- sender_name: nil,
7
- sender_location: nil,
8
- sender_uid: nil,
9
- time_recieved: nil,
10
- payload: nil,
11
- destination: '',
12
- hops: [])
13
-
14
- # package the original message
15
- message = {
16
- message: message,
17
- destination: destination,
18
- hops: hops
19
- }
20
-
21
- super(
22
- message: message,
23
- sender_name: sender_name,
24
- sender_location: sender_location,
25
- sender_uid: sender_uid,
26
- time_recieved: time_recieved,
27
- payload: payload)
28
- end
29
-
30
- def display; end
31
-
32
- def handle
33
- respond
34
- return
35
- end
36
-
37
- def respond
38
-
39
- end
40
-
41
- end
42
- end
43
- end
@@ -1,36 +0,0 @@
1
- module MeshChat
2
- module Message
3
- class Whisper < Base
4
- attr_accessor :_to
5
-
6
- def initialize(
7
- message: nil,
8
- sender_name: nil,
9
- sender_location: nil,
10
- sender_uid: nil,
11
- time_recieved: nil,
12
- payload: nil,
13
- to: '')
14
-
15
- super(
16
- message: message,
17
- sender_name: sender_name,
18
- sender_location: sender_location,
19
- sender_uid: sender_uid,
20
- time_recieved: time_recieved,
21
- payload: payload)
22
-
23
- self._to = to
24
- end
25
-
26
- def display
27
- time_sent = payload['time_sent'].to_s
28
- time = Date.parse(time_sent)
29
- time_recieved = time.strftime('%e/%m/%y %H:%I:%M')
30
-
31
- to = _to.present? ? "->#{_to}" : ''
32
- "#{time_recieved} #{sender_name}#{to} > #{message}"
33
- end
34
- end
35
- end
36
- end
@@ -1,104 +0,0 @@
1
- module MeshChat
2
- module Models
3
- class Entry < ActiveRecord::Base
4
- IPV4_WITH_PORT = /((?:(?:^|\.)(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])){4})(:\d*)?/
5
- # http://rubular.com/r/WYT09ptct3
6
- DOMAIN_WITH_PORT = /(https?:\/\/)?([\da-z\.-]+)\.?([a-z\.]{2,6})([\/\w \.-]*)*[^\/](:\d*)?/
7
-
8
- validates :alias_name,
9
- :location,
10
- :public_key, presence: true
11
-
12
- validates :uid, presence: true, uniqueness: true
13
-
14
- # ipv4 with port
15
- validates_format_of :location, with: ->(e){
16
- location = e.location || ''
17
- location.include?('//') || location.include?('localhost') ?
18
- DOMAIN_WITH_PORT :
19
- IPV4_WITH_PORT
20
- }
21
-
22
- scope :online, -> { where(online: true) }
23
- scope :offline, -> { where(online: false) }
24
-
25
- class << self
26
- def sha_preimage
27
- all.map(&:public_key).sort.join(',')
28
- end
29
-
30
- def as_sha512
31
- digest = Digest::SHA512.new
32
- digest.hexdigest sha_preimage
33
- end
34
-
35
- def as_json
36
- # must also include ourselves
37
- # so that we can pass our own public key
38
- # to those who don't have it
39
- others = all.map(&:as_json)
40
- me = Settings.identity_as_json
41
- others << me
42
- end
43
-
44
- def from_json(json)
45
- new(
46
- alias_name: json['alias'],
47
- location: json['location'],
48
- uid: json['uid'],
49
- public_key: json['publickey']
50
- )
51
- end
52
-
53
- def public_key_from_uid(uid)
54
- find_by_uid(uid).try(:public_key)
55
- end
56
-
57
- # @param [Array] theirs array of hashes representing node entries
58
- # @return [Array<-,+>] nodes only we have, and nodes only they have
59
- def diff(theirs)
60
- ours = as_json
61
- we_only_have = ours - theirs
62
- they_only_have = theirs - ours
63
-
64
- [we_only_have, they_only_have]
65
- end
66
-
67
- def import_from_file(filename)
68
- begin
69
- f = File.read(filename)
70
- hash = JSON.parse(f)
71
- n = from_json(hash)
72
- n.save
73
- n
74
- rescue => e
75
- Display.alert e.message
76
- end
77
- end
78
- end
79
-
80
- def ==(other)
81
- result = false
82
-
83
- if other.is_a?(Hash)
84
- result = as_json.values_at(*other.keys) == other.values
85
- end
86
-
87
- result || super
88
- end
89
-
90
- def as_json
91
- {
92
- 'alias' => alias_name,
93
- 'location' => location,
94
- 'uid' => uid,
95
- 'publickey' => public_key
96
- }
97
- end
98
-
99
- def as_info
100
- "#{alias_name}@#{location}"
101
- end
102
- end
103
- end
104
- end
@@ -1,83 +0,0 @@
1
- module MeshChat
2
- module Net
3
- module Client
4
- module_function
5
-
6
- # @note Either the location, node, or uid should be present
7
- #
8
- # @param [String] location (Optional) location of target
9
- # @param [String] uid (Optional) uid of target
10
- # @param [Node] node (Optional) target
11
- # @param [Message] message (Required) what to send to the target
12
- def send(location: nil, uid: nil, node: nil, message: nil)
13
- # verify node is valid
14
- node = self.node_for(location: location, uid: uid, node: node)
15
- # don't proceed if we don't have a node
16
- return unless node
17
-
18
- if Settings['uid'] == node.uid
19
- Display.debug 'avoiding sending to self'
20
- return
21
- end
22
-
23
- Thread.new(node, message) do |node, message|
24
- begin
25
- payload = Client.payload_for(node, message)
26
-
27
- Display.debug('SENDING: ' + message.type)
28
- Display.debug('SENDING: ' + message.sender.to_s)
29
- Display.debug('SENDING: ' + message.message.to_s)
30
-
31
- # TODO: this is horrible, come up with something better / abstract it
32
- begin
33
- Curl::Easy.http_post(node.location, payload.to_json) do |c|
34
- c.headers['Accept'] = 'application/json'
35
- c.headers['Content-Type'] = 'application/json'
36
- if MeshChat::Settings.debug?
37
- puts message.render
38
- c.verbose = true
39
- c.on_debug do |type, data|
40
- puts data
41
- end
42
- end
43
- end
44
- rescue => e
45
- node.update(online: false)
46
- Display.info "#{node.alias_name} has ventured offline"
47
- Display.debug("#{message.class.name}: Issue connectiong to #{node.alias_name}@#{node.location}")
48
- Display.debug(e.message)
49
- end
50
-
51
- rescue => e
52
- Display.info "Public key encryption for #{node.try(:alias_name) || 'unknown'} failed"
53
- end
54
- end
55
- end
56
-
57
- # creates a json payload
58
- def self.payload_for(node, message)
59
- request = MeshChat::Net::Request.new(node, message)
60
- { message: request.payload }
61
- end
62
-
63
- # private
64
-
65
- # @return [Node]
66
- def node_for(location: nil, uid: nil, node: nil)
67
- unless node
68
- node = Models::Entry.find_by_location(location) if location
69
- node = Models::Entry.find_by_uid(uid) if uid && !node
70
- end
71
-
72
- # TODO: also check for public key?
73
- # without the public key, the message is sent in cleartext. :-\
74
- if !(node && node.location)
75
- Display.alert "Node not found, or does not have a location. Have you imported #{location || ""}?"
76
- return
77
- end
78
-
79
- node
80
- end
81
- end
82
- end
83
- end
@@ -1,11 +0,0 @@
1
- module MeshChat
2
- module Net
3
- module Listener
4
- module Errors
5
- class NotAuthorized < StandardError; end
6
- class Forbidden < StandardError; end
7
- class BadRequest < StandardError; end
8
- end
9
- end
10
- end
11
- end
@@ -1,48 +0,0 @@
1
- module MeshChat
2
- module Net
3
- module Listener
4
- class Request
5
- attr_accessor :json, :message
6
- attr_accessor :_input
7
-
8
- def initialize(input)
9
- self._input = try_decrypt(input)
10
-
11
- begin
12
- self.json = JSON.parse(_input)
13
- rescue => e
14
- Display.debug e.message
15
- Display.debug e.backtrace.join("\n")
16
- raise Errors::BadRequest.new
17
- end
18
- self.message = process_json
19
- end
20
-
21
- private
22
-
23
- def try_decrypt(input)
24
- begin
25
- decoded = Base64.decode64(input)
26
- input = Cipher.decrypt(decoded, Settings[:privatekey])
27
- rescue => e
28
- Display.debug e.message
29
- Display.debug e.backtrace.join("\n")
30
- Display.debug input
31
- raise Errors::NotAuthorized.new(e.message)
32
- end
33
-
34
- input
35
- end
36
-
37
- def process_json
38
- type = json['type']
39
- klass = Message::TYPES[type]
40
-
41
- raise Errors::BadRequest.new(type) unless klass
42
-
43
- klass.new(payload: json)
44
- end
45
- end
46
- end
47
- end
48
- end
@@ -1,50 +0,0 @@
1
- module MeshChat
2
- module Net
3
- module Listener
4
- module RequestProcessor
5
-
6
- module_function
7
-
8
- def process(raw)
9
- request = Request.new(raw)
10
- message = request.message
11
-
12
- # TODO: wrap in debug if check
13
- Display.debug('RECEIVING: ' + message.type)
14
- Display.debug('RECEIVING: ' + message.sender.to_s)
15
- Display.debug('RECEIVING: ' + message.message.to_s)
16
-
17
- # handle the message
18
- Display.present_message message
19
-
20
- # then update the sender info in the db
21
- update_sender_info(request.json)
22
- end
23
-
24
- def update_sender_info(json)
25
- sender = json['sender']
26
-
27
- # if the sender isn't currently marked as active,
28
- # perform the server list exchange
29
- node = Node.find_by_uid(sender['uid'])
30
- raise Errors::Forbidden.new if node.nil?
31
-
32
- unless node.online?
33
- node.update(online: true)
34
- payload = Message::NodeListHash.new
35
- Client.send(
36
- location: sender['location'],
37
- message: payload)
38
- end
39
-
40
- # update the node's location/alias
41
- # as they can change this info willy nilly
42
- node.update(
43
- location: sender['location'],
44
- alias_name: sender['alias']
45
- )
46
- end
47
- end
48
- end
49
- end
50
- end
@@ -1,114 +0,0 @@
1
- require 'sinatra/base'
2
- require 'meshchat/net/listener/errors'
3
-
4
- module MeshChat
5
- module Net
6
- module Listener
7
- class Server < Sinatra::Base
8
- OK = 200
9
- BAD_REQUEST = 400
10
- NOT_AUTHORIZED = 401
11
- FORBIDDEN = 403
12
-
13
- configure :development do
14
- # only shows resulting status
15
- disable :logging
16
- # enable :logging
17
- set :bind, '0.0.0.0' #['10.10.2.29','127.0.0.1', 'localhost']
18
- set :show_exceptions, :after_handler
19
- set :threaded, true
20
- end
21
- # TODO: do we want to return an error if
22
- # we can't decrypt?
23
-
24
- def self.run!(*)
25
- # any code that should be ran
26
- # before sintra starts should go here
27
-
28
- # start the server
29
- super
30
- # code after here will not run
31
- end
32
-
33
- get '/' do
34
- process_request
35
- end
36
-
37
- post '/' do
38
- process_request
39
- end
40
-
41
- def process_request
42
- begin
43
- # form params should override
44
- # raw body
45
- raw = get_message
46
- process(raw)
47
- rescue => e
48
- Display.error e.message
49
- Display.error e.backtrace.join("\n")
50
- body e.message
51
- status 500
52
- end
53
- end
54
-
55
- def get_message
56
- # if received as form data
57
- return params[:message] if params[:message]
58
-
59
- # if received as json
60
- request_body = request.body.read
61
- json_body = JSON.parse(request_body)
62
- json_body['message']
63
- end
64
-
65
- def process(raw)
66
- # decode, etc
67
- begin
68
- RequestProcessor.process(raw)
69
- rescue Errors::NotAuthorized
70
- status_of NOT_AUTHORIZED
71
- rescue Errors::Forbidden
72
- status_of FORBIDDEN
73
- rescue Errors::BadRequest
74
- status_of BAD_REQUEST
75
- end
76
- end
77
-
78
- def status_of(s)
79
- status s
80
- Display.debug('SERVER: ' + s.inspect)
81
- body ''
82
- end
83
-
84
- # Hack away our problems
85
- # don't show the Sinatra has taken the stage message
86
- #
87
- # https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1504
88
- def self.start_server(handler, server_settings, handler_name)
89
- handler.run(self, server_settings) do |server|
90
-
91
- setup_traps
92
- set :running_server, server
93
- set :handler_name, handler_name
94
- server.threaded = settings.threaded if server.respond_to? :threaded=
95
-
96
- yield server if block_given?
97
- end
98
- end
99
-
100
- # Hack away our problems
101
- # Don't show the Sinatra quit message
102
- #
103
- # https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1420
104
- def self.quit!
105
- return unless running?
106
- # Use Thin's hard #stop! if available, otherwise just #stop.
107
- running_server.respond_to?(:stop!) ? running_server.stop! : running_server.stop
108
- set :running_server, nil
109
- set :handler_name, nil
110
- end
111
- end
112
- end
113
- end
114
- end