omf_common 6.0.0 → 6.0.2.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/bin/file_broadcaster.rb +56 -0
- data/bin/file_receiver.rb +62 -0
- data/bin/omf_keygen +21 -0
- data/bin/{monitor_topic.rb → omf_monitor_topic} +21 -8
- data/bin/omf_send_create +118 -0
- data/bin/{send_request.rb → omf_send_request} +12 -7
- data/example/engine_alt.rb +23 -24
- data/example/ls_app.yaml +21 -0
- data/lib/omf_common.rb +73 -12
- data/lib/omf_common/auth.rb +15 -0
- data/lib/omf_common/auth/certificate.rb +174 -0
- data/lib/omf_common/auth/certificate_store.rb +72 -0
- data/lib/omf_common/auth/ssh_pub_key_convert.rb +80 -0
- data/lib/omf_common/comm.rb +66 -9
- data/lib/omf_common/comm/amqp/amqp_communicator.rb +40 -13
- data/lib/omf_common/comm/amqp/amqp_file_transfer.rb +259 -0
- data/lib/omf_common/comm/amqp/amqp_topic.rb +14 -21
- data/lib/omf_common/comm/local/local_communicator.rb +31 -2
- data/lib/omf_common/comm/local/local_topic.rb +19 -3
- data/lib/omf_common/comm/topic.rb +48 -34
- data/lib/omf_common/comm/xmpp/communicator.rb +19 -10
- data/lib/omf_common/comm/xmpp/topic.rb +22 -81
- data/lib/omf_common/default_logging.rb +11 -0
- data/lib/omf_common/eventloop.rb +14 -0
- data/lib/omf_common/eventloop/em.rb +39 -6
- data/lib/omf_common/eventloop/local_evl.rb +15 -0
- data/lib/omf_common/exec_app.rb +29 -15
- data/lib/omf_common/message.rb +53 -5
- data/lib/omf_common/message/json/json_message.rb +149 -39
- data/lib/omf_common/message/xml/message.rb +112 -39
- data/lib/omf_common/protocol/6.0.rnc +5 -1
- data/lib/omf_common/protocol/6.0.rng +12 -0
- data/lib/omf_common/version.rb +1 -1
- data/omf_common.gemspec +7 -2
- data/test/fixture/omf_test.cert.pem +15 -0
- data/test/fixture/omf_test.pem +15 -0
- data/test/fixture/omf_test.pub +1 -0
- data/test/fixture/omf_test.pub.pem +6 -0
- data/test/omf_common/auth/certificate_spec.rb +113 -0
- data/test/omf_common/auth/ssh_pub_key_convert_spec.rb +13 -0
- data/test/omf_common/comm/topic_spec.rb +175 -0
- data/test/omf_common/comm/xmpp/communicator_spec.rb +15 -16
- data/test/omf_common/comm/xmpp/topic_spec.rb +63 -10
- data/test/omf_common/comm_spec.rb +66 -9
- data/test/omf_common/message/xml/message_spec.rb +43 -13
- data/test/omf_common/message_spec.rb +14 -0
- data/test/test_helper.rb +25 -0
- metadata +78 -15
- data/bin/send_create.rb +0 -94
@@ -37,5 +37,16 @@ module OmfCommon
|
|
37
37
|
def warn(*args, &block)
|
38
38
|
logger.warn(*args, &block)
|
39
39
|
end
|
40
|
+
|
41
|
+
# Log a warning message for deprecated methods
|
42
|
+
def warn_deprecation(deprecated_name, *suggest_names)
|
43
|
+
logger.warn "[DEPRECATION] '#{deprecated_name}' is deprecated. Please use '#{suggest_names.join(', ')}' instead."
|
44
|
+
end
|
45
|
+
|
46
|
+
def warn_removed(deprecated_name)
|
47
|
+
define_method(deprecated_name) do |*args, &block|
|
48
|
+
logger.warn "[DEPRECATION] '#{deprecated_name}' is deprecated and not supported. Please do not use it."
|
49
|
+
end
|
50
|
+
end
|
40
51
|
end
|
41
52
|
end
|
data/lib/omf_common/eventloop.rb
CHANGED
@@ -84,7 +84,21 @@ module OmfCommon
|
|
84
84
|
def on_stop(&block)
|
85
85
|
warn "Missing implementation 'on_stop'"
|
86
86
|
end
|
87
|
+
|
88
|
+
# Calling 'block' when having trapped an INT signal
|
89
|
+
#
|
90
|
+
def on_int_signal(&block)
|
91
|
+
# trap(:INT)
|
92
|
+
warn "Missing implementation 'on_int_signal'"
|
93
|
+
end
|
87
94
|
|
95
|
+
# Calling 'block' when having trapped a TERM signal
|
96
|
+
#
|
97
|
+
def on_term_signal(&block)
|
98
|
+
# trap(:TERM) {}
|
99
|
+
warn "Missing implementation 'on_term_signal'"
|
100
|
+
end
|
101
|
+
|
88
102
|
private
|
89
103
|
def initialize(opts = {}, &block)
|
90
104
|
#run(&block) if block
|
@@ -25,15 +25,43 @@ module OmfCommon
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
# Call 'block' in the context of a separate thread.
|
29
|
+
#
|
30
|
+
def defer(&block)
|
31
|
+
raise "Can't handle 'defer' registration before the EM is up" unless EM.reactor_running?
|
32
|
+
EM.defer do
|
33
|
+
begin
|
34
|
+
block.call()
|
35
|
+
rescue => ex
|
36
|
+
error "Exception '#{ex}'"
|
37
|
+
debug "#{ex}\n\t#{ex.backtrace.join("\n\t")}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
28
42
|
# Periodically call block every interval_sec
|
29
43
|
#
|
30
44
|
# @param [Float] interval in sec
|
31
45
|
def every(interval_sec, &block)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
46
|
+
# to allow canceling the periodic timer we need to
|
47
|
+
# hand back a reference to it which responds to 'cancel'
|
48
|
+
# As this is getting rather complex when allowing for
|
49
|
+
# registration before the EM is up and running, we simply throw
|
50
|
+
# and exception at this time.
|
51
|
+
raise "Can't handle 'every' registration before the EM is up" unless EM.reactor_running?
|
52
|
+
# if EM.reactor_running?
|
53
|
+
# EM.add_periodic_timer(interval_sec, &block)
|
54
|
+
# else
|
55
|
+
# @deferred << lambda do
|
56
|
+
# EM.add_periodic_timer(interval_sec, &block)
|
57
|
+
# end
|
58
|
+
# end
|
59
|
+
EM.add_periodic_timer(interval_sec) do
|
60
|
+
begin
|
61
|
+
block.call()
|
62
|
+
rescue => ex
|
63
|
+
error "Exception '#{ex}'"
|
64
|
+
debug "#{ex}\n\t#{ex.backtrace.join("\n\t")}"
|
37
65
|
end
|
38
66
|
end
|
39
67
|
end
|
@@ -43,7 +71,12 @@ module OmfCommon
|
|
43
71
|
@deferred.each { |proc| proc.call }
|
44
72
|
@deferred = nil
|
45
73
|
if block
|
46
|
-
|
74
|
+
begin
|
75
|
+
block.arity == 0 ? block.call : block.call(self)
|
76
|
+
rescue => ex
|
77
|
+
error "While executing run block - #{ex}"
|
78
|
+
error ex.backtrace.join("\n\t")
|
79
|
+
end
|
47
80
|
end
|
48
81
|
end
|
49
82
|
end
|
@@ -31,6 +31,21 @@ module OmfCommon
|
|
31
31
|
@tasks << [Time.now + interval_sec, block, :periodic => interval_sec]
|
32
32
|
end
|
33
33
|
|
34
|
+
# Call 'block' in the context of a separate thread.
|
35
|
+
#
|
36
|
+
def defer(&block)
|
37
|
+
@logger.note("DEFER")
|
38
|
+
Thread.new do
|
39
|
+
begin
|
40
|
+
block.call()
|
41
|
+
rescue => ex
|
42
|
+
@logger.error "Exception '#{ex}'"
|
43
|
+
@logger.debug ex.backtract.join("\n\t")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
34
49
|
def stop
|
35
50
|
@running = false
|
36
51
|
end
|
data/lib/omf_common/exec_app.rb
CHANGED
@@ -32,7 +32,7 @@ require 'fcntl'
|
|
32
32
|
# Borrows from Open3
|
33
33
|
#
|
34
34
|
class ExecApp
|
35
|
-
|
35
|
+
|
36
36
|
# Holds the pids for all active apps
|
37
37
|
@@all_apps = Hash.new
|
38
38
|
|
@@ -69,25 +69,27 @@ class ExecApp
|
|
69
69
|
#
|
70
70
|
# Run an application 'cmd' in a separate thread and monitor
|
71
71
|
# its stdout. Also send status reports to the 'observer' by
|
72
|
-
# calling its "
|
72
|
+
# calling its "call(eventType, appId, message")"
|
73
73
|
#
|
74
74
|
# @param id ID of application (used for reporting)
|
75
75
|
# @param observer Observer of application's progress
|
76
76
|
# @param cmd Command path and args
|
77
77
|
# @param map_std_err_to_out If true report stderr as stdin [false]
|
78
78
|
#
|
79
|
-
def initialize(id,
|
79
|
+
def initialize(id, cmd, map_std_err_to_out = false, working_directory = nil, &observer)
|
80
80
|
|
81
81
|
@id = id
|
82
82
|
@observer = observer
|
83
83
|
@@all_apps[id] = self
|
84
|
+
@exit_status = nil
|
85
|
+
@threads = []
|
84
86
|
|
85
87
|
pw = IO::pipe # pipe[0] for read, pipe[1] for write
|
86
88
|
pr = IO::pipe
|
87
89
|
pe = IO::pipe
|
88
90
|
|
89
91
|
logger.debug "Starting application '#{id}' - cmd: '#{cmd}'"
|
90
|
-
@observer.
|
92
|
+
@observer.call(:STARTED, id, cmd)
|
91
93
|
@pid = fork {
|
92
94
|
# child will remap pipes to std and exec cmd
|
93
95
|
pw[1].close
|
@@ -103,6 +105,7 @@ class ExecApp
|
|
103
105
|
pe[1].close
|
104
106
|
|
105
107
|
begin
|
108
|
+
Dir.chdir working_directory if working_directory
|
106
109
|
exec(cmd)
|
107
110
|
rescue => ex
|
108
111
|
cmd = cmd.join(' ') if cmd.kind_of?(Array)
|
@@ -118,23 +121,31 @@ class ExecApp
|
|
118
121
|
monitor_pipe(:stdout, pr[0])
|
119
122
|
monitor_pipe(map_std_err_to_out ? :stdout : :stderr, pe[0])
|
120
123
|
# Create thread which waits for application to exit
|
121
|
-
Thread.new(id, @pid) do |id, pid|
|
124
|
+
@threads << Thread.new(id, @pid) do |id, pid|
|
122
125
|
ret = Process.waitpid(pid)
|
123
|
-
|
126
|
+
@exit_status = $?.exitstatus
|
124
127
|
@@all_apps.delete(@id)
|
125
128
|
# app finished
|
126
|
-
if (
|
127
|
-
s = "OK"
|
129
|
+
if (@exit_status == 0) || @clean_exit
|
128
130
|
logger.debug "Application '#{id}' finished"
|
129
131
|
else
|
130
|
-
|
131
|
-
logger.debug "Application '#{id}' failed (code=#{status})"
|
132
|
+
logger.debug "Application '#{id}' failed (code=#{@exit_status})"
|
132
133
|
end
|
133
|
-
@observer.on_app_event("DONE.#{s}", @id, "status: #{status}")
|
134
134
|
end
|
135
135
|
@stdin = pw[1]
|
136
|
+
|
137
|
+
# wait for done in yet another thread
|
138
|
+
Thread.new do
|
139
|
+
@threads.each {|t| t.join }
|
140
|
+
if (@exit_status == 0) || @clean_exit
|
141
|
+
s = "OK"
|
142
|
+
else
|
143
|
+
s = "ERROR"
|
144
|
+
end
|
145
|
+
@observer.call("DONE.#{s}", @id, "status: #{@exit_status}")
|
146
|
+
end
|
136
147
|
end
|
137
|
-
|
148
|
+
|
138
149
|
private
|
139
150
|
|
140
151
|
#
|
@@ -145,16 +156,19 @@ class ExecApp
|
|
145
156
|
# @param pipe Pipe to read from
|
146
157
|
#
|
147
158
|
def monitor_pipe(name, pipe)
|
148
|
-
Thread.new() do
|
159
|
+
@threads << Thread.new() do
|
149
160
|
begin
|
150
161
|
while true do
|
151
162
|
s = pipe.readline.chomp
|
152
|
-
|
163
|
+
#puts "#{name}: #{s}"
|
164
|
+
@observer.call(name.to_s.upcase, @id, s)
|
153
165
|
end
|
154
166
|
rescue EOFError
|
155
167
|
# do nothing
|
156
|
-
|
168
|
+
#puts "++++ STOP MONITORING #{name}"
|
169
|
+
rescue => err
|
157
170
|
logger.error "monitorApp(#{@id}): #{err}"
|
171
|
+
logger.debug "#{err}\n\t#{err.backtrace.join("\n\t")}"
|
158
172
|
ensure
|
159
173
|
pipe.close
|
160
174
|
end
|
data/lib/omf_common/message.rb
CHANGED
@@ -26,9 +26,10 @@ module OmfCommon
|
|
26
26
|
}
|
27
27
|
}
|
28
28
|
@@message_class = nil
|
29
|
+
@@authenticate_messages = false
|
29
30
|
|
30
31
|
def self.create(type, properties, body = {})
|
31
|
-
@@message_class.create(type, properties, body)
|
32
|
+
@@message_class.create(type, properties || {}, body)
|
32
33
|
end
|
33
34
|
|
34
35
|
def self.create_inform_message(itype = nil, properties = {}, body = {})
|
@@ -36,10 +37,19 @@ module OmfCommon
|
|
36
37
|
create(:inform, properties, body)
|
37
38
|
end
|
38
39
|
|
39
|
-
#
|
40
|
+
# Return true if all messages will be authenticated, return false otherwise
|
40
41
|
#
|
41
|
-
def self.
|
42
|
-
@@
|
42
|
+
def self.authenticate?
|
43
|
+
@@authenticate_messages
|
44
|
+
end
|
45
|
+
|
46
|
+
# Parse message from 'str' and pass it to 'block'.
|
47
|
+
# If authnetication is on, the message will only be handed
|
48
|
+
# to 'block' if the source of the message can be authenticated.
|
49
|
+
#
|
50
|
+
def self.parse(str, content_type = nil, &block)
|
51
|
+
raise ArgumentError, 'Need message handling block' unless block
|
52
|
+
@@message_class.parse(str, content_type, &block)
|
43
53
|
end
|
44
54
|
|
45
55
|
def self.init(opts = {})
|
@@ -60,6 +70,7 @@ module OmfCommon
|
|
60
70
|
else
|
61
71
|
raise "Missing provider class info - :constructor"
|
62
72
|
end
|
73
|
+
@@authenticate_messages = opts[:authenticate] if opts[:authenticate]
|
63
74
|
end
|
64
75
|
|
65
76
|
OMF_CORE_READ.each do |pname|
|
@@ -116,7 +127,15 @@ module OmfCommon
|
|
116
127
|
raise NotImplementedError
|
117
128
|
end
|
118
129
|
|
130
|
+
def properties
|
131
|
+
raise NotImplementedError
|
132
|
+
end
|
133
|
+
|
119
134
|
def has_properties?
|
135
|
+
not properties.empty?
|
136
|
+
end
|
137
|
+
|
138
|
+
def guard?
|
120
139
|
raise NotImplementedError
|
121
140
|
end
|
122
141
|
|
@@ -138,11 +157,32 @@ module OmfCommon
|
|
138
157
|
self.class.create_inform_message(itype, properties, body)
|
139
158
|
end
|
140
159
|
|
160
|
+
# Fetch inform type
|
161
|
+
#
|
162
|
+
# When no format provided, return the value as it is.
|
163
|
+
#
|
164
|
+
# @param [Symbol] format to render itype, valid formats: :ruby, :frcp
|
165
|
+
#
|
166
|
+
def itype(format = nil)
|
167
|
+
if format && !_get_core(:itype).nil?
|
168
|
+
case format.to_sym
|
169
|
+
when :ruby
|
170
|
+
_get_core(:itype).to_s.downcase.gsub(/\./, '_')
|
171
|
+
when :frcp
|
172
|
+
_get_core(:itype).to_s.upcase.gsub(/_/, '.')
|
173
|
+
else
|
174
|
+
raise ArgumentError, "Unknown format '#{format}'. Please use ':ruby, :frcp' instead."
|
175
|
+
end
|
176
|
+
else
|
177
|
+
_get_core(:itype)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
141
181
|
def to_s
|
142
182
|
raise NotImplementedError
|
143
183
|
end
|
144
184
|
|
145
|
-
def marshall
|
185
|
+
def marshall(include_cert = false)
|
146
186
|
raise NotImplementedError
|
147
187
|
end
|
148
188
|
|
@@ -171,6 +211,14 @@ module OmfCommon
|
|
171
211
|
def _set_property(name, value, ns = nil)
|
172
212
|
raise NotImplementedError
|
173
213
|
end
|
214
|
+
|
215
|
+
def _set_core(key, value)
|
216
|
+
raise NotImplementedError
|
217
|
+
end
|
218
|
+
|
219
|
+
def _get_core(key)
|
220
|
+
raise NotImplementedError
|
221
|
+
end
|
174
222
|
end
|
175
223
|
|
176
224
|
end
|
@@ -1,42 +1,107 @@
|
|
1
1
|
|
2
2
|
require 'json'
|
3
|
+
require 'omf_common/auth'
|
4
|
+
require 'json/jwt'
|
3
5
|
|
4
6
|
module OmfCommon
|
5
7
|
class Message
|
6
8
|
class Json
|
7
9
|
class Message < OmfCommon::Message
|
8
|
-
|
10
|
+
|
11
|
+
# This maps properties in the internal representation of
|
12
|
+
# a message to names used for the JSON message
|
13
|
+
#
|
14
|
+
@@key2json_key = {
|
15
|
+
operation: :op,
|
16
|
+
res_id: :rid
|
17
|
+
}
|
9
18
|
|
10
19
|
def self.create(type, properties, body = {})
|
11
|
-
if type == :request
|
20
|
+
if type == :request
|
12
21
|
unless properties.kind_of?(Array)
|
13
22
|
raise "Expected array, but got #{properties.class} for request message"
|
14
23
|
end
|
15
24
|
properties = {select: properties}
|
16
25
|
elsif not properties.kind_of?(Hash)
|
17
26
|
raise "Expected hash, but got #{properties.class}"
|
18
|
-
end
|
27
|
+
end
|
19
28
|
content = body.merge({
|
20
|
-
|
29
|
+
op: type,
|
21
30
|
mid: SecureRandom.uuid,
|
22
|
-
|
31
|
+
props: properties
|
23
32
|
})
|
24
33
|
self.new(content)
|
25
34
|
end
|
26
|
-
|
35
|
+
|
27
36
|
def self.create_inform_message(itype = nil, properties = {}, body = {})
|
28
37
|
body[:itype] = itype if itype
|
29
38
|
create(:inform, properties, body)
|
30
39
|
end
|
31
|
-
|
40
|
+
|
32
41
|
# Create and return a message by parsing 'str'
|
33
42
|
#
|
34
|
-
def self.parse(str)
|
35
|
-
|
36
|
-
|
37
|
-
|
43
|
+
def self.parse(str, content_type, &block)
|
44
|
+
#puts "CT>> #{content_type}"
|
45
|
+
case content_type.to_s
|
46
|
+
when 'jwt'
|
47
|
+
content = parse_jwt(str, &block)
|
48
|
+
when 'text/json'
|
49
|
+
content = JSON.parse(str, :symbolize_names => true)
|
50
|
+
else
|
51
|
+
warn "Received message with unknown content type '#{content_type}'"
|
52
|
+
end
|
53
|
+
#puts "CTTT>> #{content}::#{content.class}"
|
54
|
+
msg = content ? new(content) : nil
|
55
|
+
block.call(msg) if msg
|
56
|
+
msg
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.parse_jwt(jwt_string)
|
60
|
+
key_or_secret = :skip_verification
|
61
|
+
# Code lifted from 'json-jwt-0.4.3/lib/json/jwt.rb'
|
62
|
+
case jwt_string.count('.')
|
63
|
+
when 2 # JWT / JWS
|
64
|
+
header, claims, signature = jwt_string.split('.', 3).collect do |segment|
|
65
|
+
UrlSafeBase64.decode64 segment.to_s
|
66
|
+
end
|
67
|
+
header, claims = [header, claims].collect do |json|
|
68
|
+
#MultiJson.load(json).with_indifferent_access
|
69
|
+
JSON.parse(json, :symbolize_names => true)
|
70
|
+
end
|
71
|
+
signature_base_string = jwt_string.split('.')[0, 2].join('.')
|
72
|
+
jwt = JSON::JWT.new claims
|
73
|
+
jwt.header = header
|
74
|
+
jwt.signature = signature
|
75
|
+
|
76
|
+
# NOTE:
|
77
|
+
# Some JSON libraries generates wrong format of JSON (spaces between keys and values etc.)
|
78
|
+
# So we need to use raw base64 strings for signature verification.
|
79
|
+
unless src = claims[:iss]
|
80
|
+
warn "JWT: Message is missing :iss element"
|
81
|
+
return nil
|
82
|
+
end
|
83
|
+
if cert_pem = claims[:crt]
|
84
|
+
# let's the credential store take care of it
|
85
|
+
OmfCommon::Auth::CertificateStore.instance.register_x509(cert_pem, src)
|
86
|
+
end
|
87
|
+
unless cert = OmfCommon::Auth::CertificateStore.instance.cert_for(src)
|
88
|
+
warn "JWT: Can't find cert for issuer '#{src}'"
|
89
|
+
return nil
|
90
|
+
end
|
91
|
+
|
92
|
+
unless cert.verify_cert
|
93
|
+
warn "JWT: Invalid certificate '#{cert.to_s}', NOT signed by root certificate."
|
94
|
+
end
|
95
|
+
|
96
|
+
#puts ">>> #{cert.to_x509.public_key}::#{signature_base_string}"
|
97
|
+
jwt.verify signature_base_string, cert.to_x509.public_key #unless key_or_secret == :skip_verification
|
98
|
+
JSON.parse(claims[:cnt], :symbolize_names => true)
|
99
|
+
else
|
100
|
+
warn('JWT: Invalid Format. JWT should include 2 or 3 dots.')
|
101
|
+
return nil
|
102
|
+
end
|
38
103
|
end
|
39
|
-
|
104
|
+
|
40
105
|
def each_property(&block)
|
41
106
|
@properties.each do |k, v|
|
42
107
|
#unless INTERNAL_PROPS.include?(k.to_sym)
|
@@ -44,16 +109,21 @@ module OmfCommon
|
|
44
109
|
#end
|
45
110
|
end
|
46
111
|
end
|
47
|
-
|
112
|
+
|
113
|
+
def properties
|
114
|
+
@properties
|
115
|
+
end
|
116
|
+
|
117
|
+
|
48
118
|
def has_properties?
|
49
119
|
not @properties.empty?
|
50
120
|
end
|
51
|
-
|
121
|
+
|
52
122
|
def valid?
|
53
123
|
true # don't do schema verification , yet
|
54
124
|
end
|
55
|
-
|
56
|
-
# Loop over all the unbound (sent without a value) properties
|
125
|
+
|
126
|
+
# Loop over all the unbound (sent without a value) properties
|
57
127
|
# of a request message.
|
58
128
|
#
|
59
129
|
def each_unbound_request_property(&block)
|
@@ -66,9 +136,9 @@ module OmfCommon
|
|
66
136
|
block.call(el)
|
67
137
|
end
|
68
138
|
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# Loop over all the bound (sent with a value) properties
|
139
|
+
end
|
140
|
+
|
141
|
+
# Loop over all the bound (sent with a value) properties
|
72
142
|
# of a request message.
|
73
143
|
#
|
74
144
|
def each_bound_request_property(&block)
|
@@ -83,47 +153,87 @@ module OmfCommon
|
|
83
153
|
end
|
84
154
|
end
|
85
155
|
end
|
86
|
-
end
|
87
|
-
|
88
|
-
|
156
|
+
end
|
157
|
+
|
158
|
+
|
89
159
|
def to_s
|
90
160
|
"JsonMessage: #{@content.inspect}"
|
91
161
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
162
|
+
|
163
|
+
# Marshall message into a string to be shipped across the network.
|
164
|
+
# Depending on authentication setting, the message will be signed as
|
165
|
+
# well, or maybe even dropped.
|
166
|
+
#
|
167
|
+
# @param [Topic] topic for which to marshall
|
168
|
+
#
|
169
|
+
def marshall(topic)
|
170
|
+
#puts "MARSHALL: #{@content.inspect} - #{@properties.to_hash.inspect}"
|
171
|
+
raise "Missing SRC declaration in #{@content}" unless @content[:src]
|
172
|
+
if @content[:src].is_a? OmfCommon::Comm::Topic
|
173
|
+
@content[:src] = @content[:src].id
|
174
|
+
end
|
175
|
+
#raise 'local/local' if @content[:src].id.match 'local:/local'
|
176
|
+
#puts @content.inspect
|
177
|
+
payload = @content.to_json
|
178
|
+
if self.class.authenticate?
|
179
|
+
src = @content[:src]
|
180
|
+
cert = OmfCommon::Auth::CertificateStore.instance.cert_for(src)
|
181
|
+
if cert && cert.can_sign?
|
182
|
+
debug "Found cert for '#{src} - #{cert}"
|
183
|
+
msg = {cnt: payload, iss: src}
|
184
|
+
unless @certOnTopic[k = [topic, src]]
|
185
|
+
# first time for this src on this topic, so let's send the cert along
|
186
|
+
msg[:crt] = cert.to_pem_compact
|
187
|
+
#ALWAYS ADD CERT @certOnTopic[k] = Time.now
|
188
|
+
end
|
189
|
+
#:RS256, :RS384, :RS512
|
190
|
+
p = JSON::JWT.new(msg).sign(cert.key , :RS256).to_s
|
191
|
+
#puts "SIGNED>> #{msg}"
|
192
|
+
return ['jwt', p]
|
193
|
+
end
|
194
|
+
end
|
195
|
+
['text/json', payload]
|
95
196
|
end
|
96
|
-
|
97
|
-
private
|
197
|
+
|
198
|
+
private
|
98
199
|
def initialize(content)
|
99
200
|
debug "Create message: #{content.inspect}"
|
100
|
-
|
101
|
-
unless op = content[:operation]
|
201
|
+
unless op = content[:op]
|
102
202
|
raise "Missing message type (:operation)"
|
103
203
|
end
|
104
|
-
content
|
105
|
-
|
204
|
+
@content = {}
|
205
|
+
content[:op] = op.to_sym # needs to be symbol
|
206
|
+
if src = content[:src]
|
207
|
+
content[:src] = OmfCommon.comm.create_topic(src)
|
208
|
+
end
|
209
|
+
content.each {|k,v| _set_core(k, v)}
|
210
|
+
@properties = content[:props] || []
|
106
211
|
#@properties = Hashie::Mash.new(content[:properties])
|
212
|
+
@authenticate = self.class.authenticate?
|
213
|
+
# keep track if we sent local certs on a topic. Should do this the first time
|
214
|
+
@certOnTopic = {}
|
107
215
|
end
|
108
|
-
|
216
|
+
|
109
217
|
def _set_core(key, value)
|
110
|
-
@content[key] = value
|
218
|
+
@content[(@@key2json_key[key] || key).to_sym] = value
|
111
219
|
end
|
112
220
|
|
113
221
|
def _get_core(key)
|
114
|
-
@content[key]
|
222
|
+
@content[@@key2json_key[key] || key]
|
115
223
|
end
|
116
|
-
|
117
|
-
def _set_property(key, value)
|
224
|
+
|
225
|
+
def _set_property(key, value, ns = nil)
|
226
|
+
warn "Can't handle namespaces yet" if ns
|
118
227
|
@properties[key] = value
|
119
228
|
end
|
120
229
|
|
121
|
-
def _get_property(key)
|
230
|
+
def _get_property(key, ns = nil)
|
231
|
+
warn "Can't handle namespaces yet" if ns
|
122
232
|
#puts key
|
123
233
|
@properties[key]
|
124
234
|
end
|
125
|
-
|
235
|
+
|
126
236
|
end # class
|
127
237
|
end
|
128
238
|
end
|
129
|
-
end
|
239
|
+
end
|