plezi 0.10.16 → 0.10.17

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9ba53dc3edc704550c8afdc060088aed2cd9db01
4
- data.tar.gz: 7aa792d205aabce90e999f1c5637a882c40de10a
3
+ metadata.gz: c509d0a1c5c9aa5fec5827c0f7b6a27dbf143840
4
+ data.tar.gz: c1cef78d006408e83140295a0a392553ee8b1521
5
5
  SHA512:
6
- metadata.gz: 667725a7647a0c49e81991e0d164c3729c639ecbd37e56de37cb0131ed91cf059039e2b9eba121bef365b23e89e8b0dcca57b7bcdc0b75fa547bb3949fd29161
7
- data.tar.gz: 44a1bb1546727e1e96fecfbe3e65607dcd0f9093ac4f1fb8a9161d33a119f23c739f93f9ea761abfe1536f4763a96518117b912c19de9382f6e7a6d4bbd598e9
6
+ metadata.gz: edfc62fc655f782518bc355b0fd83b6784e141b445867f4307c948b8d92dd79d5d20dbb7b843143cc4e45f4cf0a9a1867b7a9df433e952c57b117644a6c2453c
7
+ data.tar.gz: 46af810bb76558461e3933645e9e6064109228257e57aea3f09063425a3676fcf61a06d5cb96b6849aed99376f56dc29f14f794ae628b981a98d2d0e7eb774e6
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ***
4
4
 
5
+ Change log v.0.10.17
6
+
7
+ **Update**: Requires a newer version of the GRHttp server and GReactor, building on it's WSClient and HTTP decoding improvements.
8
+
9
+ **Security**: Redis connection broadcasting now enforces `safe_load`, so that even id the Redis server and it's data are compromized, it should not lead to foreign code execution. Please note that this will enforce limits on session data as well as on websocket broadcasting.
10
+
11
+ **Sessions**: Sessions are now avoided unless explicitly created or unless a websocket connection is established. The reason being that unless Redis is defined, sessions are stored in-memory and end up requiring a lot of space. File storage might be considered for future releases.
12
+
13
+ ***
14
+
5
15
  Change log v.0.10.16
6
16
 
7
17
  **Fix**: Requires a newer version of the GRHttp server, which fixs an issue with Firefox's websocket implementation.
@@ -95,7 +95,7 @@ unless defined? PLEZI_NON_DSL
95
95
  $PL_ARGV = $*.dup
96
96
 
97
97
  # sets up a generic session-token name based on the script name
98
- GRHttp.session_token = "#{($0).split(/[\\\/]/).last.split(/[\s]+/).first}_uuid"
98
+ GRHttp.session_token = "#{($0).split(/[\\\/]/).last.split(/[\s\.]+/).first}_uuid"
99
99
  # restarts the Plezi app with the same arguments as when it was started.
100
100
  #
101
101
  # EXPERIMENTAL
@@ -1,6 +1,53 @@
1
1
 
2
2
  module Plezi
3
3
 
4
+ module Base
5
+ module AutoRedis
6
+ @redis_locker ||= Mutex.new
7
+ @redis = @redis_sub_thread = nil
8
+ module_function
9
+ def inner_init_redis
10
+ return false unless ENV['PL_REDIS_URL'] && defined?(::Redis)
11
+ @redis_locker.synchronize do
12
+ return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis # repeat the test once syncing is done.
13
+ @redis_uri ||= URI.parse(ENV['PL_REDIS_URL'])
14
+ @redis.quit if @redis
15
+ @redis = ::Redis.new(host: @redis_uri.host, port: @redis_uri.port, password: @redis_uri.password)
16
+ raise "Redis connction failed for: #{ENV['PL_REDIS_URL']}" unless @redis
17
+ @redis_sub_thread = Thread.new do
18
+ begin
19
+ safe_types = [Symbol, Date, Time, Encoding, Struct, Regexp, Range, Set]
20
+ ::Redis.new(host: @redis_uri.host, port: @redis_uri.port, password: @redis_uri.password).subscribe(Plezi::Settings.redis_channel_name, Plezi::Settings.uuid) do |on|
21
+ on.message do |channel, msg|
22
+ begin
23
+ data = YAML.safe_load(msg, safe_types)
24
+ next if data[:server] == Plezi::Settings.uuid
25
+ data[:type] = Object.const_get(data[:type]) unless data[:type].nil? || data[:type] == :all
26
+ if data[:target]
27
+ GRHttp::Base::WSHandler.unicast data[:target], data
28
+ else
29
+ GRHttp::Base::WSHandler.broadcast data
30
+ end
31
+ rescue => e
32
+ GReactor.error e
33
+ end
34
+ end
35
+ end
36
+ rescue => e
37
+ GReactor.error e
38
+ retry
39
+ end
40
+ end
41
+ @redis
42
+ end
43
+ end
44
+ def get_redis
45
+ return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis
46
+ inner_init_redis
47
+ end
48
+ end
49
+ end
50
+
4
51
  module_function
5
52
 
6
53
  # Reviews the Redis connection, sets it up if it's missing and returns the Redis connection.
@@ -10,41 +57,16 @@ module Plezi
10
57
  # ENV['PL_REDIS_URL'] = ENV['REDISCLOUD_URL']`
11
58
  # or
12
59
  # ENV['PL_REDIS_URL'] = "redis://username:password@my.host:6379"
60
+ #
61
+ # Accepts an optional block that will receive the Redis connection object. i.e.
62
+ #
63
+ # Plezi.redis {|r| r.connected? }
64
+ #
65
+ # Returns the Redis object or the block's returned value (if a block is provided).
13
66
  def redis
14
- return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis
15
- return false unless defined?(Redis) && ENV['PL_REDIS_URL']
16
- @redis_locker ||= Mutex.new
17
- @redis_locker.synchronize do
18
- return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis # repeat the test once syncing is done.
19
- @redis_uri ||= URI.parse(ENV['PL_REDIS_URL'])
20
- @redis ||= Redis.new(host: @redis_uri.host, port: @redis_uri.port, password: @redis_uri.password)
21
- raise "Redis connction failed for: #{ENV['PL_REDIS_URL']}" unless @redis
22
- @redis_sub_thread = Thread.new do
23
- begin
24
- Redis.new(host: @redis_uri.host, port: @redis_uri.port, password: @redis_uri.password).subscribe(Plezi::Settings.redis_channel_name, Plezi::Settings.uuid) do |on|
25
- on.message do |channel, msg|
26
- begin
27
- data = YAML.load(msg)
28
- next if data[:server] == Plezi::Settings.uuid
29
- if data[:target]
30
- GRHttp::Base::WSHandler.unicast data[:target], data
31
- else
32
- GRHttp::Base::WSHandler.broadcast data
33
- end
34
- rescue => e
35
- Reactor.error e
36
- end
37
- end
38
- end
39
- rescue => e
40
- Reactor.error e
41
- retry
42
- end
43
- end
67
+ if r = Plezi::Base::AutoRedis.get_redis
68
+ return (block_given? ? yield(r) : r)
44
69
  end
45
- @redis
46
- rescue => e
47
- Reactor.error e
48
70
  false
49
71
  end
50
72
  alias :redis_connection :redis
@@ -19,7 +19,6 @@ module Plezi
19
19
  @host_params = request.io[:params]
20
20
  @response = response
21
21
  @cookies = request.cookies
22
- @session = response.session
23
22
  # # \@response["content-type"] ||= ::Plezi.default_content_type
24
23
  super()
25
24
  end
@@ -38,6 +37,8 @@ module Plezi
38
37
  return false if (defined?(super) && !super)
39
38
  # finish if the response was sent
40
39
  return false if response.headers_sent?
40
+ # make sure that the session object is available for websocket connections
41
+ response.session
41
42
  # complete handshake
42
43
  return self
43
44
  end
@@ -34,8 +34,14 @@ module Plezi
34
34
  # Cookies and some other data must be set BEFORE the response's headers are sent.
35
35
  attr_reader :cookies
36
36
 
37
- # Session data can be stored here (for now, session data doesn't scale - coming soon).
38
- attr_reader :session
37
+ # Session data can be stored here (session data will be stored on the Redis server, if Redis is available).
38
+ #
39
+ # The first time this method is called, the session object will be created. The session object must be created BEFORE the headers are set , if it is to be used.
40
+ #
41
+ # Sessions are not automatically created, because they are memory hogs. The one exception is the Websocket connection that will force a session object into existence.
42
+ def session
43
+ response.session
44
+ end
39
45
 
40
46
  # the HTTPResponse **OR** the WSResponse object that formats the response and sends it. use `response << data`. This object can be used to send partial data (such as headers, or partial html content) in blocking mode as well as sending data in the default non-blocking mode.
41
47
  attr_reader :response
@@ -112,7 +112,7 @@ module Plezi
112
112
  param_name = param_name[1].to_sym if param_name
113
113
 
114
114
  if param_name && dest[param_name]
115
- url << GRHttp::HTTP.encode(dest.delete(param_name).to_s, :url)
115
+ url << GRHttp::HTTP.encode_url(dest.delete(param_name))
116
116
  url << '/'
117
117
  elsif !param_name
118
118
  url << sec
@@ -125,7 +125,7 @@ module Plezi
125
125
  end
126
126
  unless dest.empty?
127
127
  add = '?'
128
- dest.each {|k, v| url << "#{add}#{GRHttp::HTTP.encode(k.to_s, :url)}=#{GRHttp::HTTP.encode(v.to_s, :url)}"; add = '&'}
128
+ dest.each {|k, v| url << "#{add}#{GRHttp::HTTP.encode_url k}=#{GRHttp::HTTP.encode_url v}"; add = '&'}
129
129
  end
130
130
  url
131
131
 
@@ -4,6 +4,7 @@ module Plezi
4
4
  module_function
5
5
  # returns a session object
6
6
  def fetch id
7
+ return Plezi::Session.new(id) if Plezi.redis # avoid a local cache if Redis is used.
7
8
  @session_cache[id] || (@session_cache[id] = Plezi::Session.new(id))
8
9
  end
9
10
  @session_cache = {}
@@ -20,7 +21,7 @@ module Plezi
20
21
  # called by the Plezi framework to initiate a session with the id requested
21
22
  def initialize id
22
23
  @id = id
23
- if (conn=Plezi.redis)
24
+ if id && (conn=Plezi.redis)
24
25
  @data=conn.hgetall(id)
25
26
  end
26
27
  @data ||= {}
@@ -193,6 +193,8 @@ module Plezi
193
193
 
194
194
  def __inner_redis_broadcast data
195
195
  return unless conn = Plezi.redis
196
+ data = data.dup
197
+ data[:type] = data[:type].name if data[:type]
196
198
  data[:server] = Plezi::Settings.uuid
197
199
  return conn.publish( ( data[:to_server] ? data[:to_server] : Plezi::Settings.redis_channel_name ), data.to_yaml ) if conn
198
200
  false
@@ -74,7 +74,7 @@ module Plezi
74
74
  #
75
75
  # defaults to the example above, which isn't a very sercure behavior, but allows for easy testing.
76
76
  def self.auth_callback &block
77
- block_given? ? (@@auth_callback = block) : ( @@auth_callback ||= (Proc.new {|service, service_token, id, email, res| Plezi.info "deafult callback called for #{service}, with response: #{res.to_s}"; cookies["#{service}_pl_auth_token".to_sym], cookies["#{service}_user_id".to_sym], cookies["#{service}_user_email".to_sym] = service_token, id, email}) )
77
+ block_given? ? (@@auth_callback = block) : ( @@auth_callback ||= (Proc.new {|service, service_token, id, email, res| Plezi.info "deafult callback called for #{service}, with response: #{res.to_s}"; session["#{service}_pl_auth_token"], session["#{service}_user_id"], session["#{service}_user_email"] = service_token, id, email}) )
78
78
  end
79
79
 
80
80
 
data/lib/plezi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Plezi
2
- VERSION = "0.10.16"
2
+ VERSION = "0.10.17"
3
3
  end
data/plezi.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "grhttp", "~> 0.0.21"
21
+ spec.add_dependency "grhttp", "~> 0.0.23"
22
22
  spec.add_development_dependency "bundler", "~> 1.7"
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
24
 
@@ -5,7 +5,7 @@
5
5
  require 'pathname'
6
6
  ## Set up root object, it might be used by the environment and\or the plezi extension gems.
7
7
  Root ||= Pathname.new(File.dirname(__FILE__)).expand_path
8
- ## Set a persistant session token id name
8
+ ## Set a persistent session token id name
9
9
  GRHttp.session_token = 'appname_uui'
10
10
  ## make sure all file access and file loading is relative to the application's root folder
11
11
  # Dir.chdir Root.to_s
@@ -2,7 +2,8 @@
2
2
  <head>
3
3
  <title>appname - Feed Me!</title>
4
4
  <meta content="width=device-width, initial-scale=1, maximum-scale=2.0, user-scalable=yes, minimal-ui=yes" name="viewport">
5
- <link href='http://fonts.googleapis.com/css?family=Shadows+Into+Light|Architects+Daughter' rel='stylesheet' type='text/css'>
5
+ <link href='https://fonts.googleapis.com/css?family=Shadows+Into+Light|Architects+Daughter' rel='stylesheet' type='text/css'>
6
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
6
7
  <style type="text/css">
7
8
  /*
8
9
  med-blue: #44518E
@@ -185,6 +186,7 @@ var websocket_fail_count = 0
185
186
 
186
187
  function init_websocket()
187
188
  {
189
+ if(websocket && websocket.readyState == 1) return true; // console.log('no need to renew socket connection');
188
190
  websocket = new WebSocket(ws_uri);
189
191
  websocket.onopen = function(e) {
190
192
  //restart fail count
@@ -14,6 +14,7 @@ var websocket_fail_limit = NaN
14
14
 
15
15
  function init_websocket()
16
16
  {
17
+ if(websocket && websocket.readyState == 1) return true; // console.log('no need to renew socket connection');
17
18
  websocket = new WebSocket(ws_uri);
18
19
  websocket.onopen = function(e) {
19
20
  // reset the count.
@@ -2,7 +2,8 @@
2
2
  <head>
3
3
  <title>appname - Feed Me!</title>
4
4
  <meta content="width=device-width, initial-scale=1, maximum-scale=2.0, user-scalable=yes, minimal-ui=yes" name="viewport">
5
- <link href='http://fonts.googleapis.com/css?family=Shadows+Into+Light|Architects+Daughter' rel='stylesheet' type='text/css'>
5
+ <link href='https://fonts.googleapis.com/css?family=Shadows+Into+Light|Architects+Daughter' rel='stylesheet' type='text/css'>
6
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
6
7
  <style type="text/css">
7
8
  /*
8
9
  med-blue: #44518E
@@ -185,6 +186,7 @@ var websocket_fail_count = 0
185
186
 
186
187
  function init_websocket()
187
188
  {
189
+ if(websocket && websocket.readyState == 1) return true; // console.log('no need to renew socket connection');
188
190
  websocket = new WebSocket(ws_uri);
189
191
  websocket.onopen = function(e) {
190
192
  //restart fail count
data/test/console CHANGED
@@ -1,11 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: UTF-8
3
3
 
4
- Dir.chdir '/Users/2Be/Ruby/plezi/plezi/'
5
-
6
4
  require 'benchmark'
7
- require "bundler/setup"
5
+ $LOAD_PATH.unshift File.expand_path(File.join('..', '..', 'lib'), __FILE__ )
8
6
  require "plezi"
7
+ require "bundler/setup"
9
8
 
10
9
  # You can add fixtures and/or initialization code here to make experimenting
11
10
  # with your gem easier. You can also use a different console, if you like.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plezi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.16
4
+ version: 0.10.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-31 00:00:00.000000000 Z
11
+ date: 2015-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grhttp
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.0.21
19
+ version: 0.0.23
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.0.21
26
+ version: 0.0.23
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement