isomorfeus-transport 1.0.0.zeta16 → 1.0.0.zeta17

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
  SHA256:
3
- metadata.gz: 797021fb762ad1532142818458f9aadedbd08b47b7022dd4e6870a68292e1383
4
- data.tar.gz: 2a18e11f99ae8ed6212bd4e7ee6651c4f8dbd7f7780bd930dd7c36b3b79292a4
3
+ metadata.gz: 22eeb2de4df1584feb9dd4cb3eb042b8a281125b82368fa3b3e173cbcf5e63bb
4
+ data.tar.gz: c9466283b250e36751be1474d8a862c3146a76e296f740c8ef4999fa91d2e8ca
5
5
  SHA512:
6
- metadata.gz: 58ade34fbf719ae7a840661e15b7ccc98b8340522af12ace8c81d79b28ea2d7c497df0a2d3fae7eafd1e62b60d22dddf0c8f6269a22eb33cc9a6864deeb0261e
7
- data.tar.gz: 1697fc639609a39a5aaf5dac32e84c8390a274bc8c560328dd84fde3cab160064725af6e5f0144e1e1b70809058977898b1d578840754f6fb68f51963ed7cb13
6
+ metadata.gz: 27ab776d59f7faf791cda3cad826634e317bbf8876811a5eb243ea84c0cf71556f3e29322116870d979f490bdc0083762829ab732c7b56eed43475df005783d7
7
+ data.tar.gz: 809334de83bd13045111ce18cbfe1b0948757e6b06473b14fa3a55991c118787f9c26a34f44b70c4b2539cd8018f861f857c2b3c90c23739797561702af939dd
@@ -10,20 +10,24 @@ if RUBY_ENGINE == 'opal'
10
10
  require 'isomorfeus/transport/client_processor'
11
11
  require 'isomorfeus/transport/websocket'
12
12
  require 'isomorfeus/transport'
13
+ require 'isomorfeus/transport/ssr_login'
13
14
  require 'lucid_channel/mixin'
14
15
  require 'lucid_channel/base'
15
16
  Isomorfeus.zeitwerk.push_dir('channels')
16
17
  Isomorfeus.add_client_init_class_name('Isomorfeus::Transport')
18
+ Isomorfeus.add_transport_init_class_name('Isomorfeus::Transport::SsrLogin') if Isomorfeus.on_ssr?
17
19
  else
18
20
  require 'base64'
19
21
  require 'digest'
22
+ require 'bcrypt'
20
23
  require 'ostruct'
21
24
  require 'socket'
22
25
  require 'oj'
23
26
  require 'websocket/driver'
24
27
  require 'active_support'
25
28
  require 'iodine'
26
- require 'isomorfeus/transport/thread_session_store'
29
+ require 'dbm'
30
+ require 'isomorfeus/transport/dbm_session_store'
27
31
  require 'isomorfeus/config'
28
32
  require 'isomorfeus/promise'
29
33
  require 'isomorfeus/transport/version'
@@ -3,6 +3,7 @@ module Isomorfeus
3
3
 
4
4
  if RUBY_ENGINE == 'opal'
5
5
  add_client_option(:api_websocket_path)
6
+ add_client_option(:cookie_eater_path)
6
7
  add_client_option(:transport_init_class_names, [])
7
8
 
8
9
  def self.add_transport_init_class_name(init_class_name)
@@ -10,16 +11,31 @@ module Isomorfeus
10
11
  end
11
12
 
12
13
  def self.current_user
13
- @current_user ||= Anonymous.new
14
+ @current_user ||= init_current_user
15
+ end
16
+
17
+ def self.init_current_user
18
+ if Isomorfeus.current_user_sid
19
+ Isomorfeus.instance_from_sid(Isomorfeus.current_user_sid)
20
+ else
21
+ Anonymous.new
22
+ end
14
23
  end
15
24
 
16
25
  def self.set_current_user(user)
17
- @current_user = user ? user : Anonymous.new
26
+ if user
27
+ @current_user = user
28
+ Isomorfeus.current_user_sid = user.to_sid
29
+ else
30
+ @current_user = Anonymous.new
31
+ end
18
32
  end
19
33
  else
20
34
  class << self
21
35
  attr_accessor :api_websocket_path
36
+ attr_accessor :cookie_eater_path
22
37
  attr_accessor :session_store
38
+ attr_accessor :cookie_dbm_path
23
39
 
24
40
  def add_middleware(middleware)
25
41
  Isomorfeus.middlewares << middleware
@@ -132,9 +148,11 @@ module Isomorfeus
132
148
  end
133
149
  end
134
150
 
135
- self.session_store = Isomorfeus::Transport::ThreadSessionStore.new # dont use this one, but we keep it here to have at least something
151
+ self.cookie_dbm_path = 'cookie'
152
+ self.session_store = Isomorfeus::Transport::DbmSessionStore.new # dont use this one, but we keep it here to have at least something
136
153
  end
137
154
 
138
155
  # defaults
139
156
  self.api_websocket_path = '/isomorfeus/api/websocket'
157
+ self.cookie_eater_path = '/isomorfeus/cookie/eat'
140
158
  end
@@ -0,0 +1,51 @@
1
+ module Isomorfeus
2
+ module Transport
3
+ class DbmSessionStore
4
+ def initialize
5
+ DBM.open(Isomorfeus.cookie_dbm_path, 0640, DBM::NEWDB).close
6
+ end
7
+
8
+ def add(session_id:, cookie:, user:, accessor:)
9
+ DBM.open(Isomorfeus.cookie_dbm_path, 0640, DBM::WRITER) do |dbm|
10
+ dbm[session_id] = Oj.dump([user.class.to_s, user.key], mode: :strict)
11
+ dbm[accessor] = cookie
12
+ end
13
+ end
14
+
15
+ def take_cookie(accessor:)
16
+ DBM.open(Isomorfeus.cookie_dbm_path, 0640, DBM::WRITER) do |dbm|
17
+ cookie = dbm[accessor]
18
+ if cookie
19
+ session_info = cookie.split('; ').first
20
+ session_id = session_info.split('=').last.strip
21
+ dbm["eaten_#{accessor}"] = session_id
22
+ dbm.delete(accessor)
23
+ else
24
+ # asked for the same cookie a second time
25
+ # can probably only be due to session hijacking
26
+ # so delete all sessions associated with that accessor
27
+ session_id = dbm["eaten_#{accessor}"]
28
+ dbm.delete(session_id) if session_id
29
+ end
30
+ cookie
31
+ end
32
+ end
33
+
34
+ def get_user(session_id:)
35
+ json = DBM.open(Isomorfeus.cookie_dbm_path, 0640, DBM::READER) do |dbm|
36
+ dbm[session_id]
37
+ end
38
+ if json
39
+ user_info = Oj.load(json, mode: :strict)
40
+ user_info[0].constantize.load(key: user_info[1]) if user_info
41
+ end
42
+ end
43
+
44
+ def remove(session_id:)
45
+ DBM.open(Isomorfeus.cookie_dbm_path, 0640, DBM::WRITER) do |dbm|
46
+ dbm.delete(session_id)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -18,26 +18,37 @@ module Isomorfeus
18
18
  user = nil
19
19
  if Isomorfeus.valid_user_class_name?(user_class_name)
20
20
  user_class = Isomorfeus.cached_user_class(user_class_name)
21
- response_agent.request['login'][user_class_name].each_key do |user_identifier|
22
- promise = user_class.promise_login(user: user_identifier, pass: response_agent.request['login'][user_class_name][user_identifier])
23
- unless promise.realized?
24
- start = Time.now
25
- until promise.realized?
26
- break if (Time.now - start) > TIMEOUT
27
- sleep 0.01
28
- end
21
+ user_identifier = response_agent.request['login'][user_class_name].keys.first
22
+ promise = user_class.promise_login(user: user_identifier, pass: response_agent.request['login'][user_class_name][user_identifier])
23
+ unless promise.realized?
24
+ start = Time.now
25
+ until promise.realized?
26
+ break if (Time.now - start) > TIMEOUT
27
+ sleep 0.01
29
28
  end
30
- user = promise.value
31
- break if user
32
29
  end
30
+ user = promise.value
33
31
  end
34
32
  if user
35
- session_cookie = "session=#{SecureRandom.uuid};max-age=2592000"
33
+ session_id = SecureRandom.uuid
34
+ session_cookie = "session=#{session_id}; SameSite=Strict; HttpOnly; Path=/; Max-Age=2592000#{'; Secure' if Isomorfeus.production?}"
35
+ session_cookie_accessor = SecureRandom.uuid
36
36
  Isomorfeus.pub_sub_client.instance_variable_set(:@isomorfeus_user, user)
37
37
  Isomorfeus.pub_sub_client.instance_variable_set(:@isomorfeus_authentication_tries, nil)
38
38
  Isomorfeus.pub_sub_client.instance_variable_set(:@isomorfeus_session_cookie, session_cookie)
39
- Isomorfeus.session_store.add(cookie: session_cookie, user: user)
40
- response_agent.agent_result = { success: 'ok', data: user.to_transport, session_cookie: session_cookie }
39
+ Isomorfeus.session_store.add(session_id: session_id, cookie: session_cookie, user: user, accessor: session_cookie_accessor)
40
+ response_agent.agent_result = { success: 'ok', data: user.to_transport, session_cookie_accessor: session_cookie_accessor }
41
+ end
42
+ end
43
+ elsif login_or_logout == 'ssr_login'
44
+ response_agent.agent_result = { error: 'Authentication failed' }
45
+ response_agent.request['ssr_login'].each_key do |session_id|
46
+ user = Isomorfeus.session_store.get_user(session_id: session_id)
47
+ if user
48
+ Isomorfeus.pub_sub_client.instance_variable_set(:@isomorfeus_user, user)
49
+ Isomorfeus.pub_sub_client.instance_variable_set(:@isomorfeus_authentication_tries, nil)
50
+ Isomorfeus.pub_sub_client.instance_variable_set(:@isomorfeus_session_cookie, nil)
51
+ response_agent.agent_result = { success: 'ok', data: user.to_transport }
41
52
  end
42
53
  end
43
54
  elsif login_or_logout == 'logout'
@@ -12,12 +12,42 @@ module Isomorfeus
12
12
  def call(env)
13
13
  if env['PATH_INFO'] == Isomorfeus.api_websocket_path
14
14
  if env['rack.upgrade?'] == :websocket
15
- # TODO get session cookie
16
15
  env['rack.upgrade'] = Isomorfeus::Transport::ServerSocketProcessor.new
17
16
  end
18
17
  WS_RESPONSE
18
+ elsif env['PATH_INFO'] == Isomorfeus.cookie_eater_path
19
+ cookie_accessor, new_path = env['QUERY_STRING'].split('=')
20
+ cookie = Isomorfeus.session_store.take_cookie(accessor: cookie_accessor)
21
+ if new_path.start_with?('/')
22
+ if cookie
23
+ [302, { 'Location' => new_path, 'Set-Cookie' => cookie }, ["Cookie eaten!"]]
24
+ else
25
+ [302, { 'Location' => new_path }, ["No Cookie!"]]
26
+ end
27
+ else
28
+ [404, {}, ["Must specify relative path!"]]
29
+ end
19
30
  else
20
- @app.call(env)
31
+ cookies = env['HTTP_COOKIE']
32
+ if cookies
33
+ cookies = cookies.split('; ')
34
+ cookie = cookies.detect { |c| c.start_with?('session=') }
35
+ if cookie
36
+ session_id = cookie[8..-1]
37
+ user = Isomorfeus.session_store.get_user(session_id: session_id)
38
+ if user
39
+ Thread.current[:isomorfeus_user] = user
40
+ Thread.current[:isomorfeus_session_id] = session_id
41
+ end
42
+ end
43
+ end
44
+ begin
45
+ result = @app.call(env)
46
+ ensure
47
+ Thread.current[:isomorfeus_user] = nil
48
+ Thread.current[:isomorfeus_session_id] = nil
49
+ end
50
+ result
21
51
  end
22
52
  end
23
53
  end
@@ -45,10 +45,8 @@ module Isomorfeus
45
45
  end
46
46
 
47
47
  def user(client)
48
- # TODO get session cooke and load user from session
49
48
  current_user = client.instance_variable_get(:@isomorfeus_user)
50
49
  return current_user if current_user
51
- # TODO get session cooke and load user from session
52
50
  Anonymous.new
53
51
  end
54
52
  end
@@ -0,0 +1,28 @@
1
+ module Isomorfeus
2
+ module Transport
3
+ class SsrLogin
4
+ def self.init
5
+ session_id = `global.IsomorfeusSessionId`
6
+ if session_id && session_id.size > 0
7
+ Isomorfeus::Transport.promise_send_path('Isomorfeus::Transport::Handler::AuthenticationHandler', 'ssr_login', session_id).then do |agent|
8
+ if agent.processed
9
+ agent.result
10
+ else
11
+ agent.processed = true
12
+ if agent.response.key?(:success)
13
+ Isomorfeus.store.dispatch(type: 'DATA_LOAD', data: agent.response[:data])
14
+ class_name = agent.response[:data].keys.first
15
+ key = agent.response[:data][class_name].keys.first
16
+ logged_in_user = Isomorfeus.cached_data_class(class_name).new(key: key)
17
+ Isomorfeus.set_current_user(logged_in_user)
18
+ else
19
+ error = agent.response[:error]
20
+ Isomorfeus.raise_error(message: "SSR Login failed, #{error}!") # triggers .fail
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,5 +1,5 @@
1
1
  module Isomorfeus
2
2
  module Transport
3
- VERSION = '1.0.0.zeta16'
3
+ VERSION = '1.0.0.zeta17'
4
4
  end
5
5
  end
@@ -10,11 +10,11 @@ module LucidAuthentication
10
10
  def execute_login(&block)
11
11
  end
12
12
 
13
- def promise_login(user: nil, pass: nil, scheme: :isomorfeus)
14
- send("promise_authentication_with_#{scheme}",user: user, pass: pass)
13
+ def promise_login(user: nil, pass: nil, scheme: :isomorfeus, &block)
14
+ send("promise_authentication_with_#{scheme}", user: user, pass: pass, &block)
15
15
  end
16
16
 
17
- def promise_authentication_with_isomorfeus(user: nil, pass: nil)
17
+ def promise_authentication_with_isomorfeus(user: nil, pass: nil, &block)
18
18
  if Isomorfeus.production?
19
19
  Isomorfeus.raise_error(message: "Connection not secure, can't login") unless Isomorfeus::Transport.socket.url.start_with?('wss:')
20
20
  else
@@ -29,12 +29,19 @@ module LucidAuthentication
29
29
  Isomorfeus.store.dispatch(type: 'DATA_LOAD', data: agent.response[:data])
30
30
  class_name = agent.response[:data].keys.first
31
31
  key = agent.response[:data][class_name].keys.first
32
-
33
- # TODO set session cookie
34
- # agent.response[:session_cookie]
35
32
  logged_in_user = Isomorfeus.cached_data_class(class_name).new(key: key)
36
- Isomorfeus.set_current_user(logged_in_user)
37
- agent.result = logged_in_user
33
+ cookie_accessor = agent.response[:session_cookie_accessor]
34
+ begin
35
+ target = if block_given?
36
+ block.call(logged_in_user)
37
+ else
38
+ `window.location.pathname`
39
+ end
40
+ rescue
41
+ target = `window.location.pathname`
42
+ end
43
+ cookie_query = "#{Isomorfeus.cookie_eater_path}?#{cookie_accessor}=#{target}"
44
+ `window.location = cookie_query` # doing page load and redirect
38
45
  else
39
46
  error = agent.response[:error]
40
47
  `console.err(error)` if error
@@ -52,9 +59,9 @@ module LucidAuthentication
52
59
 
53
60
  def promise_deauthentication_with_isomorfeus
54
61
  Isomorfeus::Transport.promise_send_path('Isomorfeus::Transport::Handler::AuthenticationHandler', 'logout', 'logout').then do |agent|
55
- # TODO unset session cookie
56
- # agent.response[:session_cookie]
62
+ `document.cookie = "session="`
57
63
  Isomorfeus.set_current_user(nil)
64
+ Isomorfeus.force_init_store!
58
65
  agent.processed = true
59
66
  agent.response.key?(:success) ? true : raise('Logout failed!')
60
67
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: isomorfeus-transport
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.zeta16
4
+ version: 1.0.0.zeta17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Biedermann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-11 00:00:00.000000000 Z
11
+ date: 2020-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -100,28 +100,28 @@ dependencies:
100
100
  requirements:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: 16.12.17
103
+ version: 16.12.18
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 16.12.17
110
+ version: 16.12.18
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: isomorfeus-policy
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - '='
116
116
  - !ruby/object:Gem::Version
117
- version: 1.0.0.zeta16
117
+ version: 1.0.0.zeta17
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - '='
123
123
  - !ruby/object:Gem::Version
124
- version: 1.0.0.zeta16
124
+ version: 1.0.0.zeta17
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: websocket-driver
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - '='
144
144
  - !ruby/object:Gem::Version
145
- version: 1.0.0.zeta16
145
+ version: 1.0.0.zeta17
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - '='
151
151
  - !ruby/object:Gem::Version
152
- version: 1.0.0.zeta16
152
+ version: 1.0.0.zeta17
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: opal-webpack-loader
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -204,6 +204,7 @@ files:
204
204
  - lib/isomorfeus/transport.rb
205
205
  - lib/isomorfeus/transport/client_processor.rb
206
206
  - lib/isomorfeus/transport/config.rb
207
+ - lib/isomorfeus/transport/dbm_session_store.rb
207
208
  - lib/isomorfeus/transport/handler/authentication_handler.rb
208
209
  - lib/isomorfeus/transport/middlewares.rb
209
210
  - lib/isomorfeus/transport/rack_middleware.rb
@@ -211,7 +212,7 @@ files:
211
212
  - lib/isomorfeus/transport/response_agent.rb
212
213
  - lib/isomorfeus/transport/server_processor.rb
213
214
  - lib/isomorfeus/transport/server_socket_processor.rb
214
- - lib/isomorfeus/transport/thread_session_store.rb
215
+ - lib/isomorfeus/transport/ssr_login.rb
215
216
  - lib/isomorfeus/transport/version.rb
216
217
  - lib/isomorfeus/transport/websocket.rb
217
218
  - lib/lucid_authentication/mixin.rb
@@ -1,20 +0,0 @@
1
- module Isomorfeus
2
- module Transport
3
- class ThreadSessionStore
4
-
5
- def add(cookie:, user:)
6
- store[cookie] = user
7
- end
8
-
9
- def remove(cookie:)
10
- store.delete(cookie)
11
- end
12
-
13
- private
14
-
15
- def store
16
- Thread.current[:isomorfeus_session_store] ||= {}
17
- end
18
- end
19
- end
20
- end