hotspotlogin 0.1.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc CHANGED
@@ -6,7 +6,13 @@ Hotspotlogin is a reimplementation in Ruby/Sinatra of the popular
6
6
  hotspotlogin.cgi used with ChilliSpot and compatible Network Access
7
7
  Controllers to provide a Captive Portal environment.
8
8
 
9
- http://github.com/gderosa/hotspotlogin.rb
9
+ This release features displaying of detailed accounting info for the end user,
10
+ and is strongly based on CoovaChilli Network Access Controller and its
11
+ JSON interface.
12
+
13
+ * http://github.com/gderosa/hotspotlogin.rb
14
+
15
+ * http://coova.org/CoovaChilli/JSON
10
16
 
11
17
  === USAGE:
12
18
 
@@ -18,37 +24,52 @@ On the command-line:
18
24
 
19
25
  $ hotspotlogin [options]
20
26
 
21
- ==== Options
27
+ ==== General Options
28
+
29
+ --[no-]daemon daemonize [by default, executes in foreground]
30
+
31
+ --log log file (ignored when --no-daemon)
32
+
33
+ --pid pid file (ignored when --no-daemon)
34
+
35
+ --port [default 4990]
36
+
37
+ --listen-address [default 0.0.0.0]
38
+
39
+ --[no-]userpassword [default true]
40
+
41
+ --[no-]log-http [default false]
22
42
 
23
- --[no-]daemon daemonize [by default, executes in foreground]
43
+ --uamsecret <PASS> optional, shared secret as in chilli.conf(5)
24
44
 
25
- --log log file (ignored when --no-daemon)
45
+ --conf <FILE> YAML configuration file, see examples/
26
46
 
27
- --pid pid file (ignored when --no-daemon)
47
+ ==== End User Interface Options
28
48
 
29
- --port [default 4990]
49
+ --interval <SECONDS> autorefresh interval
30
50
 
31
- --listen-address [default 0.0.0.0]
51
+ --logo <IMAGE FILE> will be displayed in any page as
52
+ /hotspotlogin/logo.( png | jpg | etc... )
32
53
 
33
- --[no-]userpassword [default true]
54
+ --custom-text <FRAGMENT.html>
34
55
 
35
- --[no-]log-http [default false]
56
+ --custom-footer <FRAGMENT.html>
36
57
 
37
- --uamsecret <PASS> optional, shared secret as in chilli.conf(5)
58
+ --custom-headline <TEXT> will be put inside <h1></h1>
38
59
 
39
- --conf <FILE> YAML configuration file, see examples/
60
+ --favicon <FILE>
40
61
 
41
62
  See also chilli.conf(5) manual page.
42
63
 
43
64
  ==== Unix Signals
44
65
 
45
- USR1 sync/update log file (flush buffered I/O)
66
+ USR1 sync/update log file (flush buffered I/O)
46
67
 
47
68
  == LICENSE:
48
69
 
49
70
  (The MIT License)
50
71
 
51
- Copyright (c) 2010 Guido De Rosa <guido.derosa*vemarsas.it>
72
+ Copyright (c) 2010 Guido De Rosa (guido.derosa*vemarsas.it)
52
73
 
53
74
  Permission is hereby granted, free of charge, to any person obtaining
54
75
  a copy of this software and associated documentation files (the
@@ -0,0 +1,31 @@
1
+ # Example configuration snippet on how to setup a reverse HTTPS proxy
2
+ # with Lighty (http://www.lighttpd.net).
3
+
4
+ server.modules += (
5
+ "mod_proxy"
6
+ )
7
+
8
+ # enable SSL
9
+ $SERVER["socket"] == "0.0.0.0:443" {
10
+ ssl.engine = "enable"
11
+ ssl.pemfile = "/etc/lighttpd/server.pem"
12
+ ssl.ca-file = "/etc/lighttpd/ca.crt"
13
+ }
14
+
15
+ proxy.server = (
16
+ "/hotspotlogin" => (
17
+ (
18
+ "host" => "127.0.0.1",
19
+ "port" => 4990
20
+ )
21
+ ),
22
+ # another application...
23
+ #"" => (
24
+ # (
25
+ # "host" => "127.0.0.1",
26
+ # "port" => 4567
27
+ # )
28
+ #
29
+ #)
30
+ )
31
+
@@ -4,3 +4,9 @@ port: 4991
4
4
  uamsecret: uampass
5
5
  userpassword: false
6
6
  log-http: true
7
+ interval: 300
8
+ custom-headline: My Organization Name
9
+ custom-text: /some/path/fragment.html
10
+ custom-footer: /some/other/path/fragment.html
11
+ logo: /some/path/to/mylogo.png
12
+ favicon: /path/to/favicon.ico
@@ -3,6 +3,7 @@ require 'sinatra/base'
3
3
  require 'erb'
4
4
  require 'pp'
5
5
 
6
+ require 'hotspotlogin/constants'
6
7
  require 'hotspotlogin/config'
7
8
  require 'hotspotlogin/extensions/string'
8
9
 
@@ -22,39 +23,20 @@ module HotSpotLogin
22
23
 
23
24
  result, titel, headline, bodytext = '', '', '', ''
24
25
 
25
- # TODO: This is not classy: all that JS code should not be layout.erb;
26
- # to avoid failures we have to pass all this de-facto unused variables...
27
- # Horror ;-/
26
+ before do
27
+ headers(
28
+ 'X-HotSpotLoginRb-Version' => HotSpotLogin::VERSION
29
+ )
30
+ end
31
+
28
32
  not_found do # Sinatra doesn't know this ditty ;-)
29
33
  erb(
30
34
  :"404",
31
- :locals => {
32
- :titel => 'Not Found',
33
- :headline => headline,
34
- :bodytext => bodytext,
35
- :uamip => params['uamip'],
36
- :uamport => params['uamport'],
37
- :userurl => params['userurl'],
38
- :redirurl => params['redirurl'],
39
- :timeleft => params['timeleft'],
40
- :result => nil
41
- }
35
+ :layout => false
42
36
  )
43
37
  end
44
38
 
45
- # comments adapted from hotspotlogin.php :
46
-
47
- # possible Cases:
48
- # attempt to login login=login
49
- # 1: Login successful res=success
50
- # 2: Login failed res=failed
51
- # 3: Logged out res=logoff
52
- # 4: Tried to login while already logged in res=already
53
- # 5: Not logged in yet res=notyet
54
- #11: Popup res=popup1
55
- #12: Popup res=popup2
56
- #13: Popup res=popup3
57
- # 0: It was not a form request res=""
39
+ require 'hotspotlogin/app/helpers'
58
40
 
59
41
  #Read query parameters which we care about
60
42
  # params['res']
@@ -81,9 +63,40 @@ module HotSpotLogin
81
63
  # params['redirurl']
82
64
 
83
65
 
84
- # Matches '/', '/hotspotlogin' and '/hotspotlogin.rb'
85
- get %r{^/(hotspotlogin(\.rb)?/?)?$} do
66
+ # All paths should be under /hotspotlogin, to allow easier
67
+ # setup of "conditional" HTTPS reverse proxies
68
+
69
+ get '/' do
70
+ redirect '/hotspotlogin'
71
+ end
72
+
73
+ get '/hotspotlogin/favicon.ico' do
74
+ if HotSpotLogin.config['favicon']
75
+ if File.file? HotSpotLogin.config['favicon']
76
+ send_file HotSpotLogin.config['favicon']
77
+ else
78
+ not_found
79
+ end
80
+ else
81
+ not_found
82
+ end
83
+ end
86
84
 
85
+ get '/hotspotlogin/logo.:ext' do
86
+ if HotSpotLogin.config['logo']
87
+ if
88
+ File.file?( HotSpotLogin.config['logo']) and
89
+ File.extname( HotSpotLogin.config['logo']) == ".#{params[:ext]}"
90
+ send_file HotSpotLogin.config['logo']
91
+ else
92
+ not_found
93
+ end
94
+ else
95
+ not_found
96
+ end
97
+ end
98
+
99
+ get '/hotspotlogin/?' do
87
100
  if HotSpotLogin.config['uamsecret'] and
88
101
  HotSpotLogin.config['uamsecret'].length > 0
89
102
  uamsecret = HotSpotLogin.config['uamsecret']
@@ -110,69 +123,80 @@ module HotSpotLogin
110
123
  headline = 'Logging in to HotSpot'
111
124
 
112
125
  #if uamsecret and userpassword
113
- if userpassword
126
+ if userpassword # PAP
114
127
  headers({
115
128
  'Refresh' => "0;url=http://#{params['uamip']}:#{params['uamport']}/logon?username=#{params['UserName']}&password=#{pappassword}&userurl=#{params['userurl']}"
116
129
  # NOTE: no userurl passed... why?
117
130
  # NOTE: if you pass it, nothing changes
118
131
  })
119
- else
132
+ else # CHAP
120
133
  headers({
121
134
  'Refresh' => "0;url=http://#{params['uamip']}:#{params['uamport']}/logon?username=#{params['UserName']}&response=#{response}&userurl=#{params['userurl']}"
122
135
  })
123
136
  end
124
137
  elsif params['res'] == 'success'
125
- result = 1
138
+ result = Result::SUCCESS
126
139
  titel = 'Logged in to HotSpot'
127
140
  headline = 'Logged in to HotSpot'
128
141
  bodytext = 'Welcome'
129
142
  elsif params['res'] == 'failed'
130
- result = 2
143
+ result = Result::FAILED
131
144
  titel = 'HotSpot Login Failed'
132
145
  headline = 'HotSpot Login Failed'
133
146
  elsif params['res'] == 'logoff'
134
- result = 3
147
+ result = Result::LOGOFF
135
148
  titel = 'Logged out from HotSpot'
136
149
  headline = 'Logged out from HotSpot'
137
150
  elsif params['res'] == 'already'
138
- result = 4
151
+ result = Result::ALREADY
139
152
  titel = 'Already logged in to HotSpot'
140
153
  headline = 'Already logged in to HotSpot'
141
154
  elsif params['res'] == 'notyet'
142
- result = 5
155
+ result = Result::NOTYET
143
156
  titel = 'Logged out from HotSpot'
144
157
  headline = 'Logged out from HotSpot'
145
158
  elsif params['res'] == 'popup1'
146
- result = 11
159
+ result = Result::PopUp::LOGGING_IN
147
160
  titel = 'Logging into HotSpot'
148
161
  headline = 'Logged in to HotSpot'
149
162
  elsif params['res'] == 'popup2'
150
- result = 12
163
+ result = Result::PopUp::LOGGED_IN
151
164
  titel = 'Logged in to HotSpot'
152
165
  headline = 'Logged in to HotSpot'
153
166
  elsif params['res'] == 'popup3'
154
- result= 13
167
+ result= Result::PopUp::LOGGED_OUT
155
168
  titel = 'Logged out from HotSpot'
156
169
  headline = 'Logged out from HotSpot'
157
170
  elsif params['res'] == '' or !params['res'] # not a form request: err!
158
- result = 0
171
+ result = Result::NONE
159
172
  titel = 'What do you want here?'
160
173
  headline = 'HotSpot Login Failed'
161
174
  end
162
175
 
176
+ logoext = nil
177
+ logoext =
178
+ File.extname(HotSpotLogin.config['logo']) if
179
+ File.extname(HotSpotLogin.config['logo'])
180
+
163
181
  erb(
164
182
  :hotspotlogin,
165
183
  :locals => {
166
- :titel => titel,
167
- :headline => headline,
168
- :bodytext => bodytext,
169
- :uamip => params['uamip'],
170
- :uamport => params['uamport'],
171
- :userurl => params['userurl'],
172
- #:redirurl => params['redirurl'],
173
- :redirurl => params['userurl'],
174
- :timeleft => params['timeleft'],
175
- :result => result
184
+ :titel => titel,
185
+ :headline => headline, # like 'Logged out from HotSpot'
186
+ :bodytext => bodytext,
187
+ :uamip => params['uamip'],
188
+ :uamport => params['uamport'],
189
+ :userurl => params['userurl'],
190
+ #:redirurl => params['redirurl'],
191
+ :redirurl => params['userurl'],
192
+ :timeleft => params['timeleft'], # legacy...
193
+ :interval => HotSpotLogin.config['interval'],
194
+ :custom_headline =>
195
+ HotSpotLogin.config['custom-headline'], # like "MyOrg Name"
196
+ :custom_text => HotSpotLogin.config['custom-text'],
197
+ :custom_footer => HotSpotLogin.config['custom-footer'],
198
+ :logoext => logoext,
199
+ :result => result,
176
200
  }
177
201
  )
178
202
 
@@ -0,0 +1,17 @@
1
+ require 'sinatra/base'
2
+ require 'hotspotlogin/constants'
3
+
4
+ module HotSpotLogin
5
+ class App < Sinatra::Base
6
+ helpers do
7
+ def logged_in?(result)
8
+ [
9
+ HotSpotLogin::Result::ALREADY,
10
+ HotSpotLogin::Result::SUCCESS,
11
+ HotSpotLogin::Result::PopUp::SUCCESS,
12
+ ].include? result
13
+ end
14
+ alias status_window? logged_in?
15
+ end
16
+ end
17
+ end
@@ -27,7 +27,31 @@ module HotSpotLogin
27
27
  end
28
28
 
29
29
  # Command line switches override configuration file.
30
+
31
+ opts.on('--interval SECONDS', 'autorefresh accounting/session data every SECONDS seconds') do |seconds|
32
+ @@config['interval'] = seconds.to_i
33
+ end
34
+
35
+ opts.on('--custom-headline TEXT', 'display <h1>TEXT</h1> on top of the login page, tipically your Organization name') do |text|
36
+ @@config['custom-headline'] == text
37
+ end
38
+
39
+ opts.on('--custom-text FILE', 'display HTML fragment FILE before the user stats table/login form') do |file|
40
+ @@config['custom-text'] == file
41
+ end
30
42
 
43
+ opts.on('--custom-footer FILE', 'display HTML fragment FILE after the user stats table/login form') do |file|
44
+ @@config['custom-footer'] == file
45
+ end
46
+
47
+ opts.on('--logo FILE', 'logo (of your Organization etc.)') do |file|
48
+ @@config['logo'] = file
49
+ end
50
+
51
+ opts.on('--favicon FILE', 'well, favicon ;)') do |file|
52
+ @@config['favicon'] = file
53
+ end
54
+
31
55
  opts.on('--[no-]daemon', 'become a daemon') do |daemonize|
32
56
  @@config['daemon'] = daemonize
33
57
  end
@@ -44,7 +68,7 @@ module HotSpotLogin
44
68
  @@config['uamsecret'] = uamsecret
45
69
  end
46
70
 
47
- opts.on('--[no-]userpassword', 'like setting $userpassword=1 in hotspotlogin.cgi') do |userpassword|
71
+ opts.on('--[no-]userpassword', 'like setting $userpassword=1 in hotspotlogin.cgi (use PAP instead of CHAP)') do |userpassword|
48
72
  @@config['userpassword'] = userpassword
49
73
  end
50
74
 
@@ -1,12 +1,42 @@
1
1
  module HotSpotLogin
2
2
 
3
- VERSION = '0.1.2'
3
+ VERSION = '1.0.0'
4
4
 
5
5
  DEFAULT_CONFIG = {
6
6
  'listen-address' => '0.0.0.0',
7
7
  'port' => 4990,
8
8
  'log-http' => false,
9
- 'userpassword' => true # like $userpassword in hotpotlgin.(cgi|php)
9
+ 'userpassword' => true, # like $userpassword in hotpotlgin.(cgi|php)
10
+ 'interval' => 300
10
11
  }
12
+
13
+ ROOTDIR = File.join(File.dirname(File.expand_path __FILE__), '../..')
14
+
15
+ # Corresponding GET parameters are res=success, res=failed, res=popup1, etc.
16
+ module Result
17
+ SUCCESS = 1
18
+ FAILED = 2
19
+ LOGOFF = 3 # logged out
20
+ ALREADY = 4
21
+ NOTYET = 5
22
+ POPUP1 = 11
23
+ POPUP2 = 12
24
+ POPUP3 = 13
25
+ NONE = 0 # It was not a form request
26
+
27
+ # More meaningful constants for popup windows.
28
+ module PopUp
29
+ LOGGING_IN = POPUP1
30
+ LOGGED_IN = POPUP2
31
+ LOGGED_OUT = POPUP3
32
+
33
+ # convenient aliases
34
+ LOGGING = LOGGING_IN
35
+ LOGGED = LOGGED_IN
36
+ SUCCESS = LOGGED_IN
37
+ LOGOFF = LOGGED_OUT
38
+ LOGOUT = LOGOFF
39
+ end
40
+ end
11
41
 
12
42
  end
@@ -0,0 +1,77 @@
1
+ body {
2
+ font-size: 10pt;
3
+ }
4
+ h1, h2 {
5
+ text-align: center;
6
+ font-family: sans-serif;
7
+ }
8
+ h1 {
9
+ font-size: 160%;
10
+ margin: 0.1ex 0;
11
+ }
12
+ h2 {
13
+ font-size: 135%;
14
+ margin-top: 0.1ex;
15
+ font-style: italic;
16
+ }
17
+ #powered-by {
18
+ text-align: right;
19
+ font-style: italic;
20
+ margin-right: 3em;
21
+ margin-bottom: 1ex;
22
+ font-family: sans-serif;
23
+ font-size:smaller;
24
+ }
25
+ #logo-container {
26
+ text-align: center;
27
+ margin: 0 0;
28
+ }
29
+ #form-container {
30
+ text-align: center;
31
+ }
32
+ #form-container table {
33
+ margin: 1em auto 0.5em auto;
34
+ }
35
+ #form-container table tr th {
36
+ text-align: left;
37
+ }
38
+ #logInLogOut-container {
39
+ padding: 0;
40
+ margin: 0.5em 0;
41
+ text-align: center;
42
+ }
43
+ #status-container {
44
+ text-align: center;
45
+ margin: 0 0 1em 0;
46
+ }
47
+ #status-table {
48
+ margin: auto;
49
+ border: 1px blue solid;
50
+ padding: 0.5ex;
51
+ }
52
+ #status-table th {
53
+ text-align: left;
54
+ }
55
+ #status-table td {
56
+ text-align: right;
57
+ }
58
+ #status-table th.optinfo {
59
+ font-size: smaller;
60
+ font-style: italic;
61
+ }
62
+ #submit-container {
63
+ }
64
+ #submit-container button, #submit-container input[type="submit"] {
65
+ width: 5em;
66
+ }
67
+ #custom-text {
68
+ font-size: 94%;
69
+ padding: 0 1ex;
70
+ margin-bottom: 1.5em;
71
+ }
72
+ #custom-footer {
73
+ margin-top: 2em;
74
+ font-size: small;
75
+ font-family: sans-serif;
76
+ text-align: center;
77
+ }