userbin 0.2.4 → 0.3.1

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: ce994049ebc7d12cc3311da706d0555a26441ffb
4
- data.tar.gz: 95713e6b62ab30d76ca1f269908caedc61c01116
3
+ metadata.gz: b8e6296ed0a839326618e50de24bdc44370bd0b5
4
+ data.tar.gz: 0780de9c998812f4b60d7f6df082cfa8168c5633
5
5
  SHA512:
6
- metadata.gz: aacffa1023b35ae8e94a695ead4ed09a75c059dd03bbef68272e1dc06ace938303e6d4033694115abded0de2e348e7d0b639535faa7ff0e8f7a3774962386369
7
- data.tar.gz: 2575916c9ffadbb9d9dfa2f33cb92135f5460a4308203e0e78777ff8963db5297cfed726e64a2988edebd6cd1dae2f674580a509bcdcd41d240df5284144f8ce
6
+ metadata.gz: 34e266fbe71560862f5d21095f27c73ec9ab50927a7ccb6c657490114cd6e417f397e3a3f1367f17ab6792d0a2867786241762d4b348e4de8c2c935ea9b7b743
7
+ data.tar.gz: bfaa4aa0595a9ed47f77e37306463d98974cf4391e33bfa361c63c2825f768155d006a0d382a4590ddc33d5c3fc4ebd2d4122e70e179373149692d34de40ef19
data/README.md CHANGED
@@ -3,7 +3,9 @@ Userbin for Ruby
3
3
 
4
4
  Userbin for Ruby adds user authentication, login flows and user management to your **Rails**, **Sinatra** or **Rack** app.
5
5
 
6
- [Userbin](https://userbin.com) provides a set of login, signup, and password reset forms that drop right into your application without any need of styling or writing markup. Connect your users via traditional logins or third party social networks. We take care of linking accounts across networks, resetting passwords, and keeping everything safe and secure. [Create a free account](https://userbin.com) to start accepting users in your application.
6
+ [Userbin](https://userbin.com) provides a set of login, signup, and password reset forms that drop right into your application without any need of styling or writing markup. Connect your users via traditional logins or third party social networks. We take care of linking accounts across networks, resetting passwords, and keeping everything safe and secure.
7
+
8
+ [Create a free account](https://userbin.com) at Userbin to start accepting users in your application.
7
9
 
8
10
  Installation
9
11
  ------------
@@ -19,72 +21,140 @@ Installation
19
21
  ```shell
20
22
  bundle install
21
23
  ```
22
-
24
+
23
25
  2. Configure the Userbin module with the credentials you got from signing up.
24
26
 
25
- In a Rails app, put the following code into a new file at `config/initializers/userbin.rb`
27
+ In a Rails app, put the following code into a new file at `config/initializers/userbin.rb`, and in Sinatra put it in your main application file and add `require "userbin"`.
26
28
 
27
29
  ```ruby
28
30
  Userbin.configure do |config|
29
31
  config.app_id = "YOUR_APP_ID"
30
32
  config.api_secret = "YOUR_API_SECRET"
31
- config.restricted_path = "/admin"
32
33
  end
33
34
  ```
34
35
 
35
36
  If you don't configure the `app_id` and `api_secret`, the Userbin module will read the `USERBIN_APP_ID` and `USERBIN_API_SECRET` environment variables. This may come in handy on Heroku.
36
-
37
- Set up your `restricted_path` to which users will be redirected on a successful login. Browsing to this path or a sub-path will require the user to login. Logging out redirects the user back to the root path.
38
37
 
39
38
  3. **Rack/Sinatra apps only**: Activate the Userbin Rack middleware
40
39
 
41
40
  ```ruby
42
41
  use Userbin::Authentication
43
42
  ```
44
-
45
- That's it! People are now able sign up and log in to your application.
43
+
46
44
 
47
45
  Usage
48
46
  -----
49
47
 
50
- ### Signup, login and logout
48
+ ### Forms
51
49
 
52
- NOTE: To make installation as easy as possible, markup required for the Userbin UI are automatically inserted before the closing </body> and </head> tags in your HTML. It is therefore important that these tags are present on all pages where you want to use the links below.
50
+ An easy way to integrate Userbin is via the [Widget](https://userbin.com/docs/javascript#widget), which will take care of building forms, validating input and provides a drop-in design that adapts nicely to all devices.
53
51
 
54
- These links will open up the [Userbin Widget](https://userbin.com/docs/javascript#widget) with either the login or signup form.
52
+ The Widget is fairly high level, so remember that you can still use Userbin with your [own forms](https://userbin.com) if it doesn't fit your use-case.
53
+
54
+ The following links will open up the Widget with the login or the signup form respectively.
55
55
 
56
56
  ```html
57
- <!-- put this on a public page -->
58
57
  <a class="ub-login">Log in</a>
59
- or
58
+ ```
59
+
60
+ ```html
60
61
  <a class="ub-signup">Sign up</a>
61
62
  ```
62
63
 
63
64
  The logout link will clear the session and redirect the user back to your root path:
64
65
 
65
66
  ```html
66
- <!-- put this on a restricted page -->
67
67
  <a class="ub-logout">Log out</a>
68
68
  ```
69
69
 
70
- See the [Javascript reference](https://userbin.com/docs/javascript#markup) for more info on this markup.
71
-
72
70
  ### The current user
73
71
 
74
- Userbin keeps track of the currently logged in user:
72
+ Userbin keeps track of the currently logged in user which can be accessed through the `current_user` property. This automatically taps into libraries such as the authorization solution [CanCan](https://github.com/ryanb/cancan).
75
73
 
76
74
  ```erb
77
- Welcome to your account, <%= Userbin.user.email %>
75
+ Welcome to your account, <%= current_user.email %>
78
76
  ```
79
77
 
80
- To check if a user is logged in, use the following helper:
78
+ To check if a user is logged in, use `user_logged_in?` (or its alias `user_signed_in?` if you prefer Devise conventions)
81
79
 
82
80
  ```erb
83
- <% if Userbin.authenticated? %>
81
+ <% if user_logged_in? %>
84
82
  You are logged in!
85
83
  <% end %>
86
84
  ```
87
85
 
86
+ **Rack/Sinatra apps only**: Since above helpers aren't available outside Rails, instead use `Userbin.current_user` and `Userbin.user_logged_in?`.
87
+
88
+ Configuration
89
+ -------------
90
+
91
+ The `Userbin.configure` block supports a range of options additional to the Userbin credentials. None of the following options are mandatory.
92
+
93
+ ### protected_path
94
+
95
+ By default, Userbin reloads the current page on a successful login. If you set the `protected_path` option, users will be redirected to this path instead.
96
+
97
+ Once set, this path and any sub-path of it will be protected from unauthenticated users by instead rendering a login form.
98
+
99
+ ```ruby
100
+ config.protected_path = '/dashboard'
101
+ ```
102
+
103
+ ### root_path
104
+
105
+ By default, Userbin reloads the current page on a successful logout. If you set the `root_path` option, users will be redirected to this path instead.
106
+
107
+ ```ruby
108
+ config.root_path = '/login'
109
+ ```
110
+
111
+ ### create_user and find_user
112
+
113
+ By default, `current_user` will reference a *limited* Userbin profile, enabling you to work without a database. If you override the functions `create_user` and `find_user`, the current user will instead reference one of your models. The `profile` object is an *extended* Userbin profile. For more information about the available attributes in the profile see the [Userbin profile](https://userbin.com/docs/concepts) documentation.
114
+
115
+ ```ruby
116
+ config.create_user = Proc.new { |profile|
117
+ User.create! do |user|
118
+ user.userbin_id = profile.id
119
+ user.email = profile.email
120
+ user.photo = profile.image
121
+ end
122
+ }
123
+
124
+ config.find_user = Proc.new { |userbin_id|
125
+ User.find_by_userbin_id(userbin_id)
126
+ }
127
+ ```
128
+
129
+ You'll need to migrate your users and add a reference to the Userbin profile:
130
+
131
+ ```ruby
132
+ rails g migration AddUserbinIdToUsers userbin_id:integer:index
133
+ ```
134
+
135
+ ### auto_include_tags
136
+
137
+ By default, the Userbin middleware will automatically insert a `<script>` tag before the closing `</body>` in your HTML files in order to handle forms, sessions and user tracking. This script loads everything asynchronously, so it won't affect your page load speed. However if you want to have control of this procedure, set `auto_include_tags` to false and initialize the library yourself. To do that, checkout the [Userbin.js configuration guide](https://userbin.com/docs/javascript#configuration).
138
+
139
+ ```ruby
140
+ config.auto_include_tags = false
141
+ ```
142
+
143
+
144
+ Further configuration and customization
145
+ ---------------------------------------
146
+
147
+ Your Userbin dashboard gives you access to a range of functionality:
148
+
149
+ - Configure the appearance of the login widget to feel more integrated with your service
150
+ - Connect 10+ OAuth providers like Facebook, Github and Google.
151
+ - Use Markdown to generate mobile-ready transactional emails
152
+ - Invite users to your application
153
+ - See who is logging in and when
154
+ - User management: block, remove and impersonate users
155
+ - Export all your user data from Userbin
156
+
157
+
88
158
  Documentation
89
159
  -------------
90
160
  For complete documentation go to [userbin.com/docs](https://userbin.com/docs)
@@ -1,7 +1,6 @@
1
1
  module Userbin
2
2
  class Authentication
3
3
 
4
- CLOSING_HEAD_TAG = %r{</head>}
5
4
  CLOSING_BODY_TAG = %r{</body>}
6
5
 
7
6
  def initialize(app, options = {})
@@ -25,9 +24,10 @@ module Userbin
25
24
  else
26
25
  signature, data = Userbin.authenticate!(request)
27
26
 
28
- if restrict && env["PATH_INFO"].start_with?(restrict) &&
29
- !Userbin.authenticated?
30
- return render_gateway(env["REQUEST_PATH"])
27
+ if !Userbin.authenticated? && Userbin.config.protected_path &&
28
+ env["PATH_INFO"].start_with?(Userbin.config.protected_path)
29
+
30
+ return render_gateway(env["PATH_INFO"])
31
31
  end
32
32
 
33
33
  generate_response(env, signature, data)
@@ -36,8 +36,7 @@ module Userbin
36
36
  message =
37
37
  'Userbin::SecurityError: Invalid signature. Refresh to try again.'
38
38
  headers = {
39
- 'Content-Type' => 'text/text',
40
- 'Content-Length' => message.length.to_s
39
+ 'Content-Type' => 'text/text'
41
40
  }
42
41
 
43
42
  Rack::Utils.delete_cookie_header!(
@@ -49,28 +48,36 @@ module Userbin
49
48
  end
50
49
  end
51
50
 
52
- def restrict
53
- Userbin.config.restricted_path
54
- end
55
-
56
- def link_tags(login_path)
57
- <<-LINK_TAGS
58
- <link rel="userbin:root" href="/" />
59
- <link rel="userbin:login" href="#{login_path}" />
60
- LINK_TAGS
61
- end
62
-
63
- def script_tag
51
+ def script_tag(login_path)
64
52
  script_url = ENV.fetch('USERBIN_SCRIPT_URL') {
65
53
  "//js.userbin.com"
66
54
  }
67
- str = <<-SCRIPT_TAG
68
- <script src="#{script_url}?#{Userbin.config.app_id}"></script>
69
- SCRIPT_TAG
55
+ path = login_path || Userbin.config.protected_path
56
+
57
+ tag = "<script src='#{script_url}?#{Userbin.config.app_id}'></script>\n"
58
+ tag += "<script type='text/javascript'>\n"
59
+ tag += " Userbin.config({\n"
60
+ if Userbin.config.root_path
61
+ tag += " logoutRedirectUrl: '#{Userbin.config.root_path}',\n"
62
+ end
63
+ tag += " loginRedirectUrl: '#{path}',\n" if path
64
+ tag += " reloadOnSuccess: true\n"
65
+ tag += " });\n"
66
+ tag += "</script>\n"
67
+ end
68
+
69
+ def inject_tags(body, login_path = nil)
70
+ if body[CLOSING_BODY_TAG]
71
+ body = body.gsub(CLOSING_BODY_TAG, script_tag(login_path) + '\\0')
72
+ end
73
+ body
70
74
  end
71
75
 
72
76
  def render_gateway(current_path)
77
+ script_url = ENV["USERBIN_SCRIPT_URL"] || '//js.userbin.com'
78
+
73
79
  login_page = <<-LOGIN_PAGE
80
+ <!DOCTYPE html>
74
81
  <html>
75
82
  <head>
76
83
  <title>Log in</title>
@@ -80,44 +87,34 @@ module Userbin
80
87
  </body>
81
88
  </html>
82
89
  LOGIN_PAGE
90
+
83
91
  login_page = inject_tags(login_page, current_path)
84
- [ 403,
85
- { 'Content-Type' => 'text/html',
86
- 'Content-Length' => login_page.length.to_s },
87
- [login_page]
88
- ]
89
- end
90
92
 
91
- def inject_tags(body, login_path = restrict)
92
- if body[CLOSING_HEAD_TAG]
93
- body = body.gsub(CLOSING_HEAD_TAG, link_tags(login_path) + '\\0')
94
- end
95
- if body[CLOSING_BODY_TAG]
96
- body = body.gsub(CLOSING_BODY_TAG, script_tag + '\\0')
97
- end
98
- body
93
+ headers = { 'Content-Type' => 'text/html' }
94
+
95
+ [403, headers, [login_page]]
99
96
  end
100
97
 
101
98
  def generate_response(env, signature, data)
102
99
  status, headers, response = @app.call(env)
103
- if headers['Content-Type'] && headers['Content-Type']['text/html']
104
- if response.respond_to?(:body)
105
- body = [*response.body]
106
- else
107
- body = response
108
- end
109
-
110
- if Userbin.config.auto_include_tags
111
- body = body.each.map do |chunk|
112
- inject_tags(chunk)
113
- end
114
- end
115
100
 
116
- if response.respond_to?(:body)
117
- response.body = body
118
- else
119
- response = body
120
- end
101
+ if headers['Content-Type'] && headers['Content-Type']['text/html']
102
+ if response.respond_to?(:body)
103
+ body = [*response.body]
104
+ else
105
+ body = response
106
+ end
107
+ if Userbin.config.auto_include_tags
108
+ body = body.each.map do |chunk|
109
+ inject_tags(chunk)
110
+ end
111
+ end
112
+ if response.respond_to?(:body)
113
+ response.body = body
114
+ else
115
+ response = body
116
+ end
117
+ headers['Content-Length'] = body.flatten[0].length.to_s
121
118
  end
122
119
 
123
120
  if signature && data
@@ -2,9 +2,15 @@ module Userbin
2
2
  class Configuration
3
3
  attr_accessor :app_id
4
4
  attr_accessor :api_secret
5
- attr_accessor :current_user
6
5
  attr_accessor :auto_include_tags
7
- attr_accessor :restricted_path
6
+ attr_accessor :create_user
7
+ attr_accessor :find_user
8
+ attr_accessor :protected_path
9
+ attr_accessor :root_path
10
+
11
+ # restricted_path is obsolete
12
+ alias :restricted_path :protected_path
13
+ alias :restricted_path= :protected_path=
8
14
 
9
15
  def initialize
10
16
  self.app_id = ENV["USERBIN_APP_ID"]
@@ -1,12 +1,15 @@
1
1
  module Userbin
2
2
  module AuthHelpers
3
3
  def current_user
4
- return unless Userbin.authenticated?
5
- if Userbin.config.current_user
6
- @current_user ||= Userbin.config.current_user.call(Userbin.current_user)
7
- else
8
- raise "Userbin: No method configured for returning 'current_user'"
9
- end
4
+ Userbin.current_user
5
+ end
6
+
7
+ def user_logged_in?
8
+ Userbin.user_logged_in?
9
+ end
10
+
11
+ def user_signed_in?
12
+ Userbin.user_signed_in?
10
13
  end
11
14
  end
12
15
  end
@@ -18,10 +18,8 @@ module Userbin
18
18
 
19
19
  current = Userbin::Session.new(MultiJson.decode(data))
20
20
 
21
- if current.authenticated?
22
- if now > Time.at(current.expires_at / 1000)
23
- signature, data = refresh_session(current.id)
24
- end
21
+ if now > Time.at(current.expires_at / 1000)
22
+ signature, data = refresh_session(current.id)
25
23
  end
26
24
  end
27
25
 
@@ -53,10 +51,34 @@ module Userbin
53
51
  current.authenticated? rescue false
54
52
  end
55
53
 
56
- def self.current_user
54
+ def self.user_logged_in?
55
+ authenticated?
56
+ end
57
+
58
+ def self.user_signed_in?
59
+ authenticated?
60
+ end
61
+
62
+ def self._current_user
57
63
  current.user if current
58
64
  end
59
65
 
66
+ def self.current_user
67
+ if Userbin.config.find_user
68
+ u = Userbin.config.find_user.call(_current_user.id)
69
+ return u if u
70
+ if Userbin.config.create_user
71
+ u = Userbin.config.create_user.call(_current_user)
72
+ return u if u
73
+ _current_user
74
+ else
75
+ raise UnimplementedError, "You need to implement create_user"
76
+ end
77
+ else
78
+ _current_user
79
+ end
80
+ end
81
+
60
82
  def self.user
61
83
  current_user
62
84
  end
@@ -1,3 +1,3 @@
1
1
  module Userbin
2
- VERSION = "0.2.4"
2
+ VERSION = "0.3.1"
3
3
  end
data/lib/userbin.rb CHANGED
@@ -8,7 +8,7 @@ require "userbin/basic_auth"
8
8
 
9
9
  require "userbin/railtie" if defined?(Rails::Railtie)
10
10
 
11
- api_endpoint = ENV.fetch('USERBIN_API_ENDPOINT') {
11
+ api_endpoint = ENV.fetch('USERBIN_API_ENDPOINT') {3
12
12
  "https://api.userbin.com"
13
13
  }
14
14
 
@@ -28,6 +28,7 @@ require "userbin/authentication"
28
28
 
29
29
  class Userbin::Error < Exception; end
30
30
  class Userbin::SecurityError < Userbin::Error; end
31
+ class Userbin::UnimplementedError < Userbin::Error; end
31
32
 
32
33
  module Userbin
33
34
  class << self
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: userbin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johan