Skip to content

Commit

Permalink
Fork of webref
Browse files Browse the repository at this point in the history
I want to split the current webref repository into:

* a python module ('ppf.webref') providing a flask app
* a docker container using ppf.webref

I have renamed the 'webref' repository to 'docker.webref'. Now, I am
starting a new repository 'ppf.webref' with an initial commit (this
commit) that is a copy of webref's commit
10442d33ba40f994389159f06726f8b69c65ae28.
  • Loading branch information
adrianschlatter committed Dec 16, 2023
0 parents commit bc99cbb
Show file tree
Hide file tree
Showing 16 changed files with 618 additions and 0 deletions.
36 changes: 36 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# to avoid leaking credentials to github:
sqldatabasename
sqlpassword
sqlserver
sqlusername
secrets/
docker-compose.yml
hash_password.py

# to avoid leaking references to github:
references
references/

# because this relates to my personal config:
config/www.webref.conf

# general things to ignore:
build/
dist/
*.egg-info/
*.egg
*.py[cod]
__pycache__/
*.so
*~
*.tar
*.tar.gz

# due to using tox, pytest, vscode:
.tox
.cache
.eggs/
.vscode/

# due to Mac:
**/.DS_Store
19 changes: 19 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM httpd:2.4

COPY static/ /webapp/static
COPY templates/ /webapp/templates
COPY webref.py /webapp
COPY config/webref.wsgi /webapp
COPY config/httpd.conf /usr/local/apache2/conf
COPY requirements.txt /webapp
RUN mkdir /var/run/apache2 # needed to store files for WSGI
RUN mkdir /var/www # home of www-data user
WORKDIR /webapp

RUN apt update
RUN apt install -y python3
RUN apt install -y python3-pip
RUN apt install -y libapache2-mod-wsgi-py3
RUN pip3 install -r requirements.txt --break-system-packages

CMD ["/usr/local/apache2/bin/httpd", "-D", "FOREGROUND"]
20 changes: 20 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2021 Adrian Schlatter

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
50 changes: 50 additions & 0 deletions config/httpd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
ServerName localhost
ServerAdmin root@localhost
ServerRoot /usr/local/apache2
User www-data
Group www-data
PidFile logs/httpd.pid

ServerTokens Prod
UseCanonicalName On
TraceEnable Off

Timeout 10
MaxRequestWorkers 100

Listen 0.0.0.0:80

LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule unixd_module modules/mod_unixd.so

LoadModule log_config_module modules/mod_log_config.so

LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_core_module modules/mod_authz_core.so

# apt installs mod_wsgi.so in a different folder:
LoadModule wsgi_module /usr/lib/apache2/modules/mod_wsgi.so

ErrorLogFormat "[%{cu}t] [%-m:%-l] %-a %-L %M"
LogFormat "%h %l %u [%{%Y-%m-%d %H:%M:%S}t.%{usec_frac}t] \"%r\" %>s %b \
\"%{Referer}i\" \"%{User-Agent}i\"" combined

LogLevel debug
ErrorLog logs/error.log
CustomLog logs/access.log combined

<Directory />
Require all denied
Options SymLinksIfOwnerMatch
</Directory>

<VirtualHost *:80>
WSGIDaemonProcess webref user=www-data group=www-data threads=5
WSGIScriptAlias / /webapp/webref.wsgi

<Directory /webapp>
WSGIProcessGroup webref
WSGIApplicationGroup %{GLOBAL}
Require all granted
</Directory>
</VirtualHost>
4 changes: 4 additions & 0 deletions config/webref.wsgi
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import sys
sys.path.insert(0, '/webapp')

from webref import app as application
22 changes: 22 additions & 0 deletions docker-compose_templ.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
services:
webref:
image: webref
build: .
ports:
- "7000:80"
volumes:
- <path to JabRef's General File Directory>:/webapp/references
secrets:
- sqlusername
- sqlpassword
- sqlserver
- sqldatabasename
secrets:
sqlusername:
file: ./secrets/sqlusername
sqlpassword:
file: ./secrets/sqlpassword
sqlserver:
file: ./secrets/sqlserver
sqldatabasename:
file: ./secrets/sqldatabasename
91 changes: 91 additions & 0 deletions docs/DevNotes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Development Notes

## Docker Lessons

* Web server must listen on 0.0.0.0:80: Docker port mapping does not work
otherwise (127.0.0.1:80 is not enough).
* Running apache in the foreground (as it's usually done inside a docker
container) has unexpected consequences: Apache reacts to SIGWINCH
(WINdow CHange SIGnal) by restarting. Therefore, resizing the terminal
stops the container...


## Deployment to a Synology NAS

Build docker image:

```
docker build -t webref:0.x .
```

Then, save this image into a tar-ball:

```
docker save webref:0.x | gzip > webref-0.x.tar.gz
```

Copy this to your NAS where you run:

```
docker load < webref-0.x.tar.gz
```

Stop your existing webref container and delete it using the commands:

```
docker container ls
docker container stop <hexcode>
docker container rm <hexcode>
```

Go into your directory with your docker-compose.yml and run (maybe after
changing the version number inside docker-compose.yml):

```
docker-compose up --detach
```

We want https://webref.ourdomain.com to be handled by the webref
docker container => need reverse proxy. Also, we want Synology to handle
https certificates. I.e., we want the traffic decrypted before it reaches
our docker container. Synology's web interface is not
flexible enough to do this properly. It is still possible, however,
but we have to use a terminal:
[This article](https://primalcortex.wordpress.com/2018/05/07/synology-reverse-proxy-revisited-again/?unapproved=18819&moderation-hash=e368f1dda03465bca9880d8de938786a#comment-18819)
is useful. The config we put in '/etc/nginx/conf.d/server.webref.conf' is:

```
server {
listen 80;
server_name webref.ourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name webref.ourdomain.com;
add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload" always;
location / {
proxy_pass http://localhost:7000;
}
}
```

This assumes your webref container has mapped internal port 80 to host port
7000. Also, it assumes that the NAS's https certificate is valid for
webref.ourdomain.com (listed as "Subject alternative name:").

Make sure to run

```nginx -s reload```

to activate your new configuration


## Ugly

* Docker image httpd:2.4 has apache in /usr/local/apache2. But apt installs
additional apache modules (mod_wsgi) in /usr/lib/apache2.
96 changes: 96 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# WebRef

WebRef is a web interface to a [JabRef SQL database](https://docs.jabref.org/collaborative-work/sqldatabase).
It allows you to access your references from anywhere in the world and from
any device with a web browser. You do not need to install Java, you
do not need to install an app. Any non-archaic phone, tablet, PC, Mac, or
Raspberry Pi will do.

Create a JabRef database (using your normal JabRef) and configure WebRef
to point to this database. Voila: Your references just became accessible
worldwide.

Note: WebRef provides *read-only* access to your library. To add, edit, or
delete entries from your library, you still need a standard JabRef installation
somewhere.

<p align="middle">
<img alt="Screenshot" src="imgs/webref_screenshot.png" height=180>
</p>


## Installation

You need:

* JabRef: To create, edit, and extend your library
* Docker: To create and run docker images


Steps:

* Clone this repo
* Create a suitable docker-compose.yml (use
[docker-compose_templ.yml](../docker-compose_templ.yml) as a starting point)
* Create the following text files (assuming you did not change the paths
from the template docker-compose.yml):
- ./secrets/sqlusername: Username used to access your JabRef database
- ./secrets/sqlpassword: Password for that username
- ./secrets/sqlserver: The sql server holding your JabRef database
- ./secrets/sqldatabasename: The name of your JabRef database
* Run ```docker-compose up```
* Point your webbrowser to localhost:7000 (or where you configured your
WebRef to be)

This will start WebRef on your local machine which is nice for testing.
To get the most out of WebRef, you will probably want to
run this docker image on a web server.

As we have not created any users yet, we can't login. To create
users, open your JabRef database (the one named in ./secrets/sqldatabasename)
and run this sql-code (make sure you don't have a table with this name
already):

```
create table user (
id INT auto_increment,
username varchar(20) character set utf8 not null,
password char(80) character set ascii not null,
primary key (id),
unique(username)
)
```

Now we have a user table but no users in it, yet. Let's find a password and hash
it with the following python code (of course, we replace the dummy password
with your own password beforehand):

```
import bcrypt
password = 'This is my password'
bytes = password.encode('utf-8')
salt = bcrypt.gensalt()
print(bcrypt.hashpw(bytes, salt))
```

The output looks something like this:

```
b'$2b$12$1royHRBq6o/mbDdO7LjR8eaThWYErI6HLLdn7MBfajtpRLlwWSJ8m'
```

Now add your user to the user table in you JabRef database using this sql-code
(again, replace "webref" with your username and the password hash with the
hash you generated above):

```
insert into user (username, password)
values (
"webref",
"$2b$12$1royHRBq6o/mbDdO7LjR8eaThWYErI6HLLdn7MBfajtpRLlwWSJ8m"
);
```

Now we are ready to go.
Binary file added docs/imgs/webref_screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
bcrypt==4.0.1
blinker==1.7.0
click==8.1.3
Flask==2.3.3
Flask-Bcrypt==1.0.1
Flask-Login==0.6.2
Flask-SQLAlchemy==3.0.3
flask-talisman==1.0.0
Flask-WTF==1.1.1
greenlet==2.0.2
importlib-metadata==6.1.0
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.2
ppf-jabref==0.1.0
PyMySQL==1.0.3
SQLAlchemy==2.0.7
typing-extensions==4.5.0
Werkzeug==2.3.8
WTForms==3.0.1
zipp==3.15.0
21 changes: 21 additions & 0 deletions static/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

$(document).ready(function () {
// this is the id of the form
$("#search_form").submit(function (e) {
e.preventDefault(); // avoid to execute the actual submit of the form.

var form = $(this);
var url = form.attr('action');

$.ajax({
type: "POST",
url: url,
data: form.serialize(), // serializes the form's elements.
success: function (data) {
document.getElementById("entry_table").innerHTML = data;
}
});
});
// trigger submit to get the initial table of entries:
$("#search_form").submit();
});
Loading

0 comments on commit bc99cbb

Please sign in to comment.