hotspotlogin 0.1.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }