version up eggs.
[slapos.git] / stack / monitor / webfile-directory / index.cgi.in
1 #!{{ extra_eggs_interpreter }}
2
3 import cgi
4 import cgitb
5 import Cookie
6 import base64
7 import hashlib
8 import hmac
9 import jinja2
10 import os
11 import subprocess
12 import urllib
13
14 cgitb.enable(display=0, logdir="/tmp/cgi.log")
15
16 form = cgi.FieldStorage()
17 cookie = Cookie.SimpleCookie()
18
19 cgi_path = "{{ cgi_directory }}"
20
21 monitor_password_path = "{{ monitor_password_path }}"
22 monitor_password_script_path = "{{ monitor_password_script_path }}"
23
24 monitor_apache_password_command = "{{ apache_update_command }}"
25
26 monitor_rewrite = "{{ ' '.join(rewrite_element.keys())  }}"
27
28 ########
29 # Password functions
30 #######
31 def crypt(word, salt="$$"):
32   salt = salt.split("$")
33   algo = salt[0] or 'sha1'
34   if algo in hashlib.algorithms:
35     H = getattr(hashlib, algo)
36   elif algo == "plain":
37     return "%s$%s" % (algo, word)
38   else:
39     raise ValueError
40   rounds = min(max(0, int(salt[1])), 30) if salt[1] else 9
41   salt = salt[2] or base64.b64encode(os.urandom(12), "./")
42   h = hmac.new(salt, word, H).digest()
43   for x in xrange(1, 1 << rounds):
44     h = H(h).digest()
45   return "%s$%s$%s$%s" % (algo, rounds, salt,
46     base64.b64encode(h, "./").rstrip("="))
47
48 def is_password_set():
49   if not os.path.exists(monitor_password_path):
50     return False
51   hashed_password = open(monitor_password_path, 'r').read()
52   try:
53     void, algo, salt, hsh = hashed_password.split('$')
54   except ValueError:
55     return False
56   return True
57
58 def set_password(raw_password):
59   hashed_password = crypt(raw_password)
60   subprocess.check_call(monitor_apache_password_command + " %s" % raw_password,
61                         shell=True)
62   open(monitor_password_path, 'w').write(hashed_password)
63
64
65 def check_password(raw_password):
66   """
67   Returns a boolean of whether the raw_password was correct. Handles
68   encryption formats behind the scenes.
69   """
70   if not os.path.exists(monitor_password_path) or not raw_password:
71     return False
72   hashed_password = open(monitor_password_path, 'r').read()
73   return hashed_password == crypt(raw_password, hashed_password)
74 ### End of password functions
75
76 def forward_form():
77   command = os.path.join(cgi_path, form['posting-script'].value)
78   params_dict = {}
79   for f in form:
80     params_dict[f] = form[f].value
81   del params_dict['posting-script']
82   os.environ['QUERY_STRING'] = urllib.urlencode(params_dict)
83   try:
84     if os.access(command, os.X_OK):
85       print '\n', subprocess.check_output([command])
86   except subprocess.CalledProcessError:
87     print "There is a problem with sub-process"
88     pass
89
90
91 def return_document(command=None):
92   if not command:
93     script = form['script'].value
94     command = os.path.join(cgi_path, script)
95   #XXX this functions should be called only for display,
96   #so a priori it doesn't need form data
97   os.environ['QUERY_STRING'] = ''
98   try:
99     if os.access(command, os.X_OK):
100       print '\n', subprocess.check_output([command])
101     elif os.access(command, os.R_OK):
102       print open(command).read()
103     else:
104       raise OSError
105   except (subprocess.CalledProcessError, OSError) as e:
106     print "<p>Error :</p><pre>%s</pre>" % e
107
108
109 def make_menu():
110   # Transform deep-2 tree in json
111   folder_list = {}
112   for folder in os.listdir(cgi_path):
113     if os.path.isdir(os.path.join(cgi_path, folder)):
114       folder_list[folder] = []
115   for folder in folder_list:
116     for file in os.listdir(os.path.join(cgi_path, folder)):
117       if os.path.isfile(os.path.join(cgi_path, folder, file)):
118         folder_list[folder].append(file)
119   return folder_list
120
121
122 def get_cookie_password():
123   cookie_string = os.environ.get('HTTP_COOKIE')
124   if cookie_string:
125     cookie.load(cookie_string)
126     try:
127       return cookie['password'].value
128     except KeyError:
129       pass
130   return None
131
132 def set_cookie_password(password):
133   cookie['password'] = password
134   print cookie, "; Path=/; HttpOnly"
135
136
137 # Beginning of response
138 print "Content-Type: text/html"
139
140 password = None
141
142 # Check if user is logged
143 if "password_2" in form and "password" in form:
144   password_2 = form['password_2'].value
145   password_1 = form['password'].value
146   password = get_cookie_password()
147   if not is_password_set() or check_password(password):
148     if password_2 == password_1:
149       password = password_1
150       set_password(password)
151       set_cookie_password(password)
152 elif "password" in form:
153   password = form['password'].value
154   if is_password_set() and check_password(password):
155     set_cookie_password(password)
156 else:
157   password = get_cookie_password()
158 print '\n'
159
160
161 if not is_password_set():
162   return_document(monitor_password_script_path)
163 elif not check_password(password):
164   print "<html><head>"
165   print """
166     <link rel="stylesheet" href="static/pure-min.css">
167     <link rel="stylesheet" href="static/style.css">"""
168   print "</head><body>"
169   if password is None:
170     print "<h1>This is the monitoring interface</h1>"
171   else:
172     print "<h1>Error</h1><p>Wrong password</p>"
173   print """
174   <p>Please enter the monitor_password in the next field to access the data</p>
175   <form action="/index.cgi" method="post" class="pure-form-aligned">
176     Password : <input type="password" name="password">
177     <button type="submit" class="pure-button pure-button-primary">Access</button>
178   </form>
179   </body></html>"""
180 # redirection to the required script/page
181 else:
182   print
183   if "posting-script" in form:
184     forward_form()
185   elif "script" in form:
186     return_document()
187   else:
188     html_base = jinja2.Template(open('{{ index_template }}').read())
189     print
190     print html_base.render(tree=make_menu(), default_page="{{ default_page }}", monitor_rewrite=monitor_rewrite)