Skip to content
Snippets Groups Projects
Commit 227623ac authored by Dorothee Hueser's avatar Dorothee Hueser
Browse files

learning how to set up a web application using web.py

parents
No related branches found
No related tags found
No related merge requests found
README.md 0 → 100644
# Learning web.py:
## How to use https
### Install python required packages
```bash
python3 -m pip web.py --user
python3 -m pip flup
python3 -m pip psycopg2-binary
```
### make a self-signed certificate:
```bash
openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
```
in my example I used the phrase: `dorothee`
```
Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:Germany
Locality Name (eg, city) []:Braunschweig
Organization Name (eg, company) [Internet Widgits Pty Ltd]:PTB
Organizational Unit Name (eg, section) []:FB51
Common Name (e.g. server FQDN or YOUR name) []:dorothee
Email Address []:dorothee.hueser@ptb.de
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:struggle
An optional company name []:PTB
```
### Install cheroot
(which is the one to be used for current web.py version > 0.40 the older ones had wsgiserver, which does not run with the newer ones)
```
python3 -m pip install cheroot
```
### Then, in the code, e.g. `hallo2.py`:
```python
from cheroot.server import HTTPServer
from cheroot.ssl.builtin import BuiltinSSLAdapter
HTTPServer.ssl_adapter = BuiltinSSLAdapter(
certificate='server.crt',
private_key='server.key')
```
then let it run by command line calling in a shell
```bash
python3 hello2.py
```
this asks 4 time `Enter PEM pass phrase:` and each time entering `dorothee` finally told the url
`https://0.0.0.0:8080/`;
if port 8080 has already been used for some other web application, one can define a different port, e.g. 1234:
```bash
python3 hello2.py 1234
```
### Calling server in a browser
https://0.0.0.0:8080/
after entering this to the browser, the browser complains that the sefmade certificates are not trust worthy, after clicking on _advanded_ and then _yes, trust, take the risk_ or something like that, the tiny 'hello, world'-Application shows up on the client's browser window.
On the command line of the server ,the http communication returns
messages, the complete communication looks like this:
```
Enter PEM pass phrase:
Enter PEM pass phrase:
Enter PEM pass phrase:
Enter PEM pass phrase:
https://0.0.0.0:8080/
127.0.0.1:53160 - - [21/Aug/2020 15:03:55] "HTTP/1.1 GET /" - 200 OK
127.0.0.1:53160 - - [21/Aug/2020 15:03:55] "HTTP/1.1 GET /favicon.ico" - 404 Not Found
```
We will design some beautiful favicon later ;-)
### Running behind the PTB proxy
This was very easy, testing it on an PTB internal host, on n12179 it worked successfully with the very same selfmade certificates generated on the other computer.
As n12179 is a computer located at my office, not only virtually at PTB, but physically, I could enter 'https://n12179:8080/' to a browser on my windows PTB computer that is in PTB virtually via VPN client, delivering the desired 'hello, world' after confirming in advanced mode of the browser that I trust and take the risk.
### Running with subsequent closure of console
Entering the pass phrase cannot be avoided and __cannot__ be performed by
```
./hallo2.py 1234 < dorothee
```
with 1234 some chosen port/socket
However, it __can__ be realized as follows
1. enter `nohup ./hallo2.py 1234`
2. this will ask for the pass phrase and you can enter it here
3. `<ctrl> <Z>` and then `bg`
if you do the third step without using `nohup` in the first step, the process will be terminated when closing the console/shell. With using `nohup` the process continues to run after closing the shell.
### Try to avoid pass phrase entry - not good, this idea was rejected
```
hueser01@n16751:~/Documents/1-Digitalisierung/learn_webpy$ openssl req -nodes -new -x509 -keyout dorokey.pem -out dorocert.pem
Can't load /home/hueser01/.rnd into RNG
139738277839296:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/home/hueser01/.rnd
Generating a RSA private key
.............................................................+++++
............................................................................+++++
writing new private key to 'dorokey.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:Germany
Locality Name (eg, city) []:Braunschweig
Organization Name (eg, company) [Internet Widgits Pty Ltd]:PTB
Organizational Unit Name (eg, section) []:FB51
Common Name (e.g. server FQDN or YOUR name) []:dorothee
```
## Building a web site
### Rendering html
define a variable, e.g. named `render`, which manages the path to all the html-files, which is usually called `templates`, and the name of the main html file (the frame), which is usually called `base.html`:
```
render = web.template.render('templates', base='base')
```
If a web site is accessed, the start page the user should receive is the `index.html`.
The web application, we could call it `webapp.py`, that only delivers a tiny start page might look as follows:
```python
import web
urls = (
'/', 'index',
)
render = web.template.render('templates', base='base')
class index:
def GET(self):
data = {}
data['one'] = 'my nice Title'
data['two'] = 'moin moin'
return render.index(data)
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
```
and the two html files that lie in the directory `templates` might look like this:
base.html (which will be the frame for all pages, not only the index.html)
```html
$def with (content)
<html>
<head>
<title>Rauheitsanalyse</title>
<meta charset="utf-8" />
</head>
<body>
$:content
<hr>
<i>created: Dorothee Hüser, 2020-08-21, last edit: 2020-08-21</i>
</body>
</html>
```
and the index.html:
```
$def with (data)
<h2>${data['one']}</h2>
<p>At Hamburg we say ${data['two']}</p>
```
### Several pages of a site
If another page shall be reached via some link or submitting a form, e.g. by
```
$def with (data)
<h2>${data['one']}</h2>
<p>At Hamburg we say ${data['two']}</p>
<p><a href="tst">go to next page</a></p>
```
the routes need to be administrated, i.e. the assignment of the url name to the class names. This is done via the structure, which we here called `urls` and which is passed to `app = web.application(urls, globals())`, with defining the list of pairs, e.g. by
```python
import web
urls = (
'/', 'index',
'/tst', 'dosomething'
)
render = web.template.render('templates', base='base')
class dosomething:
def GET(self):
return "do something else"
class index:
def GET(self):
data = {}
data['one'] = 'my nice Title'
data['two'] = 'moin moin'
return render.index(data)
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
```
In this example, the `/` and `tst` denote the url names and `index` the class which will be called if http requests `/` and `dosomething` the class which will be called if http requests `tst`.
File added
File added
File added
File added
-----BEGIN CERTIFICATE-----
MIID/TCCAuWgAwIBAgIUdj7BGZVY74qStGIJRLo3RZ0GWG4wDQYJKoZIhvcNAQEL
BQAwgY0xCzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdHZXJtYW55MRUwEwYDVQQHDAxC
cmF1bnNjaHdlaWcxDDAKBgNVBAoMA1BUQjENMAsGA1UECwwERkI1MTERMA8GA1UE
AwwIZG9yb3RoZWUxJTAjBgkqhkiG9w0BCQEWFmRvcm90aGVlLmh1ZXNlckBwdGIu
ZGUwHhcNMjAwODIxMTQxOTA5WhcNMjAwOTIwMTQxOTA5WjCBjTELMAkGA1UEBhMC
REUxEDAOBgNVBAgMB0dlcm1hbnkxFTATBgNVBAcMDEJyYXVuc2Nod2VpZzEMMAoG
A1UECgwDUFRCMQ0wCwYDVQQLDARGQjUxMREwDwYDVQQDDAhkb3JvdGhlZTElMCMG
CSqGSIb3DQEJARYWZG9yb3RoZWUuaHVlc2VyQHB0Yi5kZTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAME1+1Qev8vlmIY+pkvD8aBRpuuMif7xKsSaXZAn
txVV7W6nDV/DfXcZePTQ8H94mK9uRwCKjlY3t/rPec1Ms4EQPXIQouMmvXTKdoJN
RoKc1IZqavJnPa/oryqCHqUoE68PChK05/PTylEdEPUnk+EY1fCQjx9QDWQ21H3r
nDQyL1Gz+4dat622YTqPiG+HvGU3bl11W2DdBWVEwk0Cf7sjcoQ7QrTqRO6vl54S
3uPbdlAyAVS4g2xhtrrQxWkHgaFKEogp4Drsqkosu15y+qeDn48mEm31AlF82IMB
kVICjbVoVFBAX9hhvJdNcSQkPpcKAR44Wv/eE+36k6hEBWcCAwEAAaNTMFEwHQYD
VR0OBBYEFM41upOjeH4iJDzyssIHHhvwrlBBMB8GA1UdIwQYMBaAFM41upOjeH4i
JDzyssIHHhvwrlBBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
AGJpWXa5WI2TVdUPiv6NsqvI9BiFGahcAtyYI9L98H60pTH2KRNFc2wiJ9mqWxm1
ZHwEao6TPTU91RuDvJYSPDESj2E8S83nFbAWMtjFjSM8VAKqbyrxXm4NO5sevFR7
g664mStpBSB+mYSG4kl3XdBbjVte0ynO7qWC3golxc1160u9BxDGupB1zyRHVlWn
AKsl/PiXvFUw1lQ3MT368MsChYj232Cbtvsrc1BkRTliMTg3tn+lIrXuMJWxExBB
l9Ur3K9r4od/OJvVzljNczE66mVckZXAq7L1h+pRwjQ4SIw3QBYS9/SPa4CVqUgL
4ALIMpHMEK4z5NMkHxkFy6o=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBNftUHr/L5ZiG
PqZLw/GgUabrjIn+8SrEml2QJ7cVVe1upw1fw313GXj00PB/eJivbkcAio5WN7f6
z3nNTLOBED1yEKLjJr10ynaCTUaCnNSGamryZz2v6K8qgh6lKBOvDwoStOfz08pR
HRD1J5PhGNXwkI8fUA1kNtR965w0Mi9Rs/uHWrettmE6j4hvh7xlN25ddVtg3QVl
RMJNAn+7I3KEO0K06kTur5eeEt7j23ZQMgFUuINsYba60MVpB4GhShKIKeA67KpK
LLtecvqng5+PJhJt9QJRfNiDAZFSAo21aFRQQF/YYbyXTXEkJD6XCgEeOFr/3hPt
+pOoRAVnAgMBAAECggEAchMTLtlw2EvYv/ohaT5pXQSYjx5NI470d1vEviYUvK4d
H2XWSaI8Y6NQfQsX08s6KunrVfB4lYMURytUeNg+a4dRIBWedosa9OfNDKXfaaJ7
AFm4hyJZk5DIS0rEGTMOXB9/DQhuotF69GU66+PQNejZ980CE7TKE08kKqx/b3jj
QneRiXHro1mE1I56nRl2I8uRhCu6VRPXkzhsy8BzclzfewTGucmtIfIBFMcEt1vH
OYh/HFIbbT7GrazlhsbxOs+f3FoYyjKJd9yRKl1f8/tglNT7OoHj/KIYirKjFz2X
yXS56IfzWsdwDRBw+SsnVCsVchhR07D3pJCQ5mCr4QKBgQDgEoacJ3hTJ6xzT9RB
k5WU7/9jp4obMXf9v+NJLRfcQPS+JbO1+vuvjteawKN9WOC0iGkqK00vbh/UQnja
oZs2MvlLxiJbCM3nfs8EUfCz9IgQFobTpDkf2TQFLwPMpLj3XGarsA2LGcyivwAg
/sOspJ3E3wYoCMVXADLqfKhO2QKBgQDcvbkMv0BLDohfl76u03NRJMiKROH8J2oi
E5qAyOvEw3+9EDvgoHiMOGedVnsiaRAEV5DJDRF1NbmEEeCfWGqdOD5rTF7YF6x9
yWhSAMFZ48zO1oT3T99vkp2bybw7P/khOV2FBfeNZH5ZgDn0UX3xISENs7gHPx0A
zIopctbOPwKBgGUY1rUjtc1G7C7GyMyhiu687eyHje9A/ZN2fVTpzIcqo4IbPp8P
03jdKPgAjIMkk5XAqjpFeTi6JhA9wYtbOM1WaFZA2gVazpPxCfQ4CDMZVD51+3UH
9mIhPLBOCxfNBktM3GIAN8wX4tVW+fbpG14Mk8Zcncl4U5kyVMapYcLZAoGAdZqO
0H/EXTis52ENMk9tjLmwLhps286T+PvAwQRKuFX/5FaV0CMulmYmrei5Saf35JhS
hwrzViL9Z6OurLaKdqDUgI37qd1TBOEdNzM30BBRuZEI3kornGHcnndoVZjLviu1
6302WppDxqNOPSB9nM4tsgMh9JpndVmD8nlAgDkCgYEAvJkkOn5lnUThEbYR/wwC
3ApawWLstk+0qAMKqkq1eDCpA6xIql04NHo/QuoodSbMv9+WyIbnUQ3EOy1u3fgS
CEAAb+QIUg8WeIxANkUxstbhaWeseyI/TWB/OQvjjuBZIEQbCK1CNxYwlNfNaZWP
slunr4mVn6o18Xm6h/8fDbU=
-----END PRIVATE KEY-----
hallo.py 0 → 100644
import web
from web.wsgiserver import CherryPyWSGIServer # SSL
#CherryPyWSGIServer.ssl_certificate = "/home/hueser01/Documents/1-Digitalisierung/learn_webpy/myserver.crt"
#CherryPyWSGIServer.ssl_private_key = "/home/hueser01/Documents/1-Digitalisierung/learn_webpy/myserver.key"
CherryPyWSGIServer.ssl_certificate = "/etc/ssl/doroserver.crt"
CherryPyWSGIServer.ssl_private_key = "/etc/ssl/doroserver.key"
urls = (
'/', 'index'
)
class index:
def GET(self):
return "Hello, world!"
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
\ No newline at end of file
#!/usr/bin/env python3
import web
from cheroot.server import HTTPServer
from cheroot.ssl.builtin import BuiltinSSLAdapter
HTTPServer.ssl_adapter = BuiltinSSLAdapter(
certificate='./server.crt',
private_key='./server.key')
urls = (
'/', 'index'
)
class index:
def GET(self):
return "Hello, world 2!"
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
\ No newline at end of file
import web
from cheroot.server import HTTPServer
from cheroot.ssl.builtin import BuiltinSSLAdapter
HTTPServer.ssl_adapter = BuiltinSSLAdapter(
certificate='./dorocert.pem',
private_key='./dorokey.pem')
urls = (
'/', 'index'
)
class index:
def GET(self):
return "Hello, world 3!"
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
\ No newline at end of file
#!/usr/bin/env python3
import web
from http.server import HTTPServer, BaseHTTPRequestHandler, SimpleHTTPRequestHandler
import ssl
httpd = HTTPServer(('localhost', 4443), SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket (httpd.socket, certfile='./server.crt', keyfile='server.key', server_side=True)
httpd.serve_forever()
urls = (
'/', 'index'
)
class index:
def GET(self):
return "Hello, world 4!"
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
\ No newline at end of file
log.txt 0 → 100644
https://0.0.0.0:8080/
Traceback (most recent call last):
File "hallo3.py", line 19, in <module>
app.run()
File "/home/hueser01/.local/lib/python3.6/site-packages/web/application.py", line 360, in run
return wsgi.runwsgi(self.wsgifunc(*middleware))
File "/home/hueser01/.local/lib/python3.6/site-packages/web/wsgi.py", line 66, in runwsgi
return httpserver.runsimple(func, server_addr)
File "/home/hueser01/.local/lib/python3.6/site-packages/web/httpserver.py", line 176, in runsimple
server.start()
File "/home/hueser01/.local/lib/python3.6/site-packages/cheroot/server.py", line 1813, in start
self.prepare()
File "/home/hueser01/.local/lib/python3.6/site-packages/cheroot/server.py", line 1772, in prepare
raise socket.error(msg)
OSError: No socket could be created -- (('0.0.0.0', 8080): [Errno 98] Address already in use)
Error in HTTPServer.tick
Traceback (most recent call last):
File "/home/hueser01/.local/lib/python3.6/site-packages/cheroot/server.py", line 1788, in serve
self.tick()
File "/home/hueser01/.local/lib/python3.6/site-packages/cheroot/server.py", line 2023, in tick
conn = self.connections.get_conn(self.socket)
File "/home/hueser01/.local/lib/python3.6/site-packages/cheroot/connections.py", line 188, in get_conn
return self._from_server_socket(server_socket)
File "/home/hueser01/.local/lib/python3.6/site-packages/cheroot/connections.py", line 207, in _from_server_socket
s, ssl_env = self.server.ssl_adapter.wrap(s)
File "/home/hueser01/.local/lib/python3.6/site-packages/cheroot/ssl/builtin.py", line 278, in wrap
sock, do_handshake_on_connect=True, server_side=True,
File "/usr/lib/python3.6/ssl.py", line 407, in wrap_socket
_context=self, _session=session)
File "/usr/lib/python3.6/ssl.py", line 817, in __init__
self.do_handshake()
File "/usr/lib/python3.6/ssl.py", line 1077, in do_handshake
self._sslobj.do_handshake()
File "/usr/lib/python3.6/ssl.py", line 689, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: SSLV3_ALERT_BAD_CERTIFICATE] sslv3 alert bad certificate (_ssl.c:852)
Traceback (most recent call last):
File "./hallo2.py", line 8, in <module>
private_key='./server.key')
File "/home/hueser01/.local/lib/python3.6/site-packages/cheroot/ssl/builtin.py", line 226, in __init__
self.context.load_cert_chain(certificate, private_key)
OSError: [Errno 22] Invalid argument
Traceback (most recent call last):
File "./hallo2.py", line 8, in <module>
private_key='./server.key')
File "/home/hueser01/.local/lib/python3.6/site-packages/cheroot/ssl/builtin.py", line 226, in __init__
self.context.load_cert_chain(certificate, private_key)
OSError: [Errno 22] Invalid argument
https://0.0.0.0:2121/
Traceback (most recent call last):
File "./hallo2.py", line 20, in <module>
app.run()
File "/home/hueser01/.local/lib/python3.6/site-packages/web/application.py", line 360, in run
return wsgi.runwsgi(self.wsgifunc(*middleware))
File "/home/hueser01/.local/lib/python3.6/site-packages/web/wsgi.py", line 66, in runwsgi
return httpserver.runsimple(func, server_addr)
File "/home/hueser01/.local/lib/python3.6/site-packages/web/httpserver.py", line 176, in runsimple
server.start()
File "/home/hueser01/.local/lib/python3.6/site-packages/cheroot/server.py", line 1813, in start
self.prepare()
File "/home/hueser01/.local/lib/python3.6/site-packages/cheroot/server.py", line 1772, in prepare
raise socket.error(msg)
OSError: No socket could be created -- (('0.0.0.0', 2121): [Errno 98] Address already in use)
dorothee
dorothee
dorothee
dorothee
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIICnjCCAgcCFBqAIX5ypkrMEhZkNU4xStUUaDUxMA0GCSqGSIb3DQEBCwUAMIGN
MQswCQYDVQQGEwJERTEQMA4GA1UECAwHR2VybWFueTEVMBMGA1UEBwwMQnJhdW5z
Y2h3ZWlnMQwwCgYDVQQKDANQVEIxDTALBgNVBAsMBEZCNTExETAPBgNVBAMMCGRv
cm90aGVlMSUwIwYJKoZIhvcNAQkBFhZkb3JvdGhlZS5odWVzZXJAcHRiLmRlMB4X
DTIwMDgyMTExMTgzMFoXDTIxMDgyMTExMTgzMFowgY0xCzAJBgNVBAYTAkRFMRAw
DgYDVQQIDAdHZXJtYW55MRUwEwYDVQQHDAxCcmF1bnNjaHdlaWcxDDAKBgNVBAoM
A1BUQjENMAsGA1UECwwERkI1MTERMA8GA1UEAwwIZG9yb3RoZWUxJTAjBgkqhkiG
9w0BCQEWFmRvcm90aGVlLmh1ZXNlckBwdGIuZGUwgZ8wDQYJKoZIhvcNAQEBBQAD
gY0AMIGJAoGBAMpa4AkoPmfkE8gX8u317VqPLqyc2ZaAn84VavIfXJIX0PcFCUWo
KLSyy7kxAat3n9i/V/0QT2/9js1V52IikK7b5kLgmlFRVITubrlSzXxMgSUHH7LA
XZHFnCmrhp14lkPzh0FlVKYALQy9mnics7vq6q7UfamzorYhJ0ZiMYlRAgMBAAEw
DQYJKoZIhvcNAQELBQADgYEAPG6m9OzkUx9BR9jV1+m6bp1JbBSJT7kbkZMBm2jZ
gt8O/lE8q1JdGtUz0v4ZDhMfYecAdCbRDZLtPgjWZJRnh07j3mVNzloJduH6euVO
Ip0RkJUyaxta8T+plX24+VlgUjSoyE6dlnLrwC0Ly7kl4eGuaC6MSi0Y9v7l8w5I
GRo=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE REQUEST-----
MIIB+zCCAWQCAQAwgY0xCzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdHZXJtYW55MRUw
EwYDVQQHDAxCcmF1bnNjaHdlaWcxDDAKBgNVBAoMA1BUQjENMAsGA1UECwwERkI1
MTERMA8GA1UEAwwIZG9yb3RoZWUxJTAjBgkqhkiG9w0BCQEWFmRvcm90aGVlLmh1
ZXNlckBwdGIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMpa4AkoPmfk
E8gX8u317VqPLqyc2ZaAn84VavIfXJIX0PcFCUWoKLSyy7kxAat3n9i/V/0QT2/9
js1V52IikK7b5kLgmlFRVITubrlSzXxMgSUHH7LAXZHFnCmrhp14lkPzh0FlVKYA
LQy9mnics7vq6q7UfamzorYhJ0ZiMYlRAgMBAAGgLTASBgkqhkiG9w0BCQIxBQwD
UFRCMBcGCSqGSIb3DQEJBzEKDAhzdHJ1Z2dsZTANBgkqhkiG9w0BAQsFAAOBgQCq
ziAhDveiwUZYXfPGsqRweo+Ot7VFv0UFjSMGpqEF+HfldqxnKwwCDIRS8i7BT4uR
adToKRMjQG/n7tabywZowgReJCU4fNzsrHer8/vFKk4HryXPoV5W2nZMvsoHGUSn
uep6TjOCySJz1HbxpLfbghsBsIWeWAhfzgJUPhrUSw==
-----END CERTIFICATE REQUEST-----
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,AE9D1E653B4020FB
7maev+fIaAYoanNLmlkF7w2kAB6QEeSV9sEomYaUarf1Qr3DP/LQyStZvg+DNUiv
ZNbjOOL7UKX89WU9XwKMPPA0SGF6HsL9/mLOinwtngooz88jYhNKnOpLL2tpI0vb
mHG7//aWUbnjigOOoZy3FqMW4Oty3Ms3R8VTMoXPOJZfgpxP+XRnyVvTWV/aiPRD
t8UkyDOHP3d9hEOnDJPc3wUZzZKQp/4913epBiVRFmThyU03B3Wdd/a0ad2PdgVc
wxYk5emPt6JwSiGG5X47PCFC7dj8SQ2KvgpLx/afh4Mqwt2Ej4LH+N7FW3h/oLJw
I/yhLwM30ZWw5twrJ2una3S/LcyPyozAsi0KC9WhYfhAdMVQpDaCQZNiLVxLeFbf
8HozulFUWm4GdkncvBAyP4ykqK5fcdbvhx7doiViRMj3Ej3M/JB+Mkmh1F1rCAys
Q9k/W3Vkd43OJebSjhjrIncxdbl44pLpOkZqnzB9etq9c7xGBkSb0mIIK9ly+lyk
sCGcjbEhJhErHRhFOcs2Hwqj1vqNf7IIZ0DQnNY3XtC+hAZx/2ey5vcsir9fp110
TJoE5VhcW+nw3dlWrevAjjboKZdVQ91v8nv7uwtV2dZBsnK6Dl6u4rqWWMjmNHQs
UkJD29t1NCV9oyToa7aFVx8zYh8tXMGjG3+cTQM8ErptXKoHBttN9jIGY/tv22d0
6zjN5EsvqpiuIf80dtyy6xolSCrXCija2Cr6WRCfS53dJqrvvefbKK35RYFlkRW7
CJGr7OZhpohQjTIr0Lhng+IdACcNBA6HL33EehedXiOA924Rz2DF1g==
-----END RSA PRIVATE KEY-----
$def with (content)
<html>
<head>
<title>Rauheitsanalyse</title>
<meta charset="utf-8" />
</head>
<body>
$:content
<hr>
<i>created: Dorothee Hüser, 2020-08-21, last edit: 2020-08-21</i>
</body>
</html>
\ No newline at end of file
$def with (data)
<h2>${data['one']}</h2>
<p>At Hamburg we say ${data['two']}</p>
<p><a href="tst">go to next page</a></p>
tst.sh 0 → 100755
#!/bin/bash
./hallo2.py
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment