7869ff83ba
* Add support for authenticated static photo URLs, leveraging the NGINX module ngx_http_auth_request. The README is updated with an example NGINX config how to set this up on the proxy side. * In settings.json a new SignedPhoto section is added: not enabled by default. * PhotoURL will append a ?jwt= token to the /static/photos/ path for the current user, which expires after 30 seconds. * When SignedPhoto is enabled, it will enforce that the JWT token is valid and matches the username of the current logged-in user, or else will return with a 403 Forbidden error.
219 lines
8.1 KiB
Markdown
219 lines
8.1 KiB
Markdown
# nonshy website
|
|
|
|
This is the source code to the main [nonshy.com](https://www.nonshy.com/)
|
|
website. It is written in Go and released under the GNU General Public
|
|
License.
|
|
|
|
This website is open source and if you'd like to help work on it (fix bugs
|
|
or contribute new features), you may sign up an account on the
|
|
[code.nonshy.com](https://code.nonshy.com/) server. See the
|
|
[CONTRIBUTING.md](CONTRIBUTING.md) file for details.
|
|
|
|
## Dependencies
|
|
|
|
You may need to run the following services along with this app:
|
|
|
|
* A **Redis cache** server: [redis.io](https://redis.io)
|
|
* (Optional) a **PostgreSQL database:** [postgresql.org](https://www.postgresql.org/)
|
|
|
|
The website can also run out of a local SQLite database which is convenient
|
|
for local development. The production server runs on PostgreSQL and the
|
|
web app is primarily designed for that.
|
|
|
|
## Building the App
|
|
|
|
This app is written in Go: [go.dev](https://go.dev). You can probably
|
|
get it from your package manager, e.g.
|
|
|
|
* macOS: `brew install golang` with homebrew: [brew.sh](https://brew.sh)
|
|
* Linux: it's in your package manager, e.g. `apt install golang`
|
|
|
|
Use the Makefile (with GNU `make` or similar):
|
|
|
|
* `make setup`: install Go dependencies
|
|
* `make build`: builds the program to ./nonshy
|
|
* `make run`: run the app from Go sources in debug mode
|
|
|
|
Or read the Makefile to see what the underlying `go` commands are,
|
|
e.g. `go run cmd/nonshy/main.go web`
|
|
|
|
## Configuring
|
|
|
|
On first run it will generate a `settings.json` file in the current
|
|
working directory (which is intended to be the root of the git clone,
|
|
with the ./web folder). Edit it to configure mail settings or choose
|
|
a database.
|
|
|
|
For simple local development, just set `"UseSQLite": true` and the
|
|
app will run with a SQLite database.
|
|
|
|
### Postgres is Highly Recommended
|
|
|
|
This website is intended to run under PostgreSQL and some of its
|
|
features leverage Postgres specific extensions. For quick local
|
|
development, SQLite will work fine but some website features will
|
|
be disabled and error messages given. These include:
|
|
|
|
* Location features such as "Who's Nearby" (PostGIS extension)
|
|
* "Newest" tab on the forums: to deduplicate comments by most recent
|
|
thread depends on Postgres, SQLite will always show all latest
|
|
comments without deduplication.
|
|
|
|
### PostGIS Extension for PostgreSQL
|
|
|
|
For the "Who's Nearby" feature to work you will need a PostgreSQL
|
|
database with the PostGIS geospatial extension installed. Usually
|
|
it might be a matter of `dnf install postgis` and activating the
|
|
extension on your nonshy database as your superuser (postgres):
|
|
|
|
```psql
|
|
create extension postgis;
|
|
```
|
|
|
|
If you get errors like "Type geography not found" from Postgres when
|
|
running distance based searches, this is the likely culprit.
|
|
|
|
### Signed Photo URLs (NGINX)
|
|
|
|
The website supports "signed photo" URLs that can help protect the direct
|
|
links to user photos (their /static/photos/*.jpg paths) to ensure only
|
|
logged-in and authorized users are able to access those links.
|
|
|
|
This feature is not enabled (enforcing) by default, as it relies on
|
|
cooperation with the NGINX reverse proxy server
|
|
(module ngx_http_auth_request).
|
|
|
|
In your NGINX config, set your /static/ path to leverage NGINX auth_request
|
|
like so:
|
|
|
|
```nginx
|
|
server {
|
|
# your boilerplate server info (SSL, etc.) - not relevant to this example.
|
|
listen 80 default_server;
|
|
listen [::]:80 default_server;
|
|
|
|
# Relevant: setting the /static/ URL on NGINX to be an alias to your local
|
|
# nonshy static folder on disk. In this example, the git clone for the
|
|
# website was at /home/www-user/git/nonshy/website, so that ./web/static/
|
|
# is the local path where static files (e.g., photos) are uploaded.
|
|
location /static/ {
|
|
# Important: auth_request tells NGINX to do subrequest authentication
|
|
# on requests into the /static/ URI of your website.
|
|
auth_request /static-auth;
|
|
|
|
# standard NGINX alias commands.
|
|
alias /home/www-user/git/nonshy/website/web/static/;
|
|
autoindex off;
|
|
}
|
|
|
|
# Configure the internal subrequest auth path.
|
|
# Note: the path "/static-auth" can be anything you want.
|
|
location = /static-auth {
|
|
internal; # this is an internal route for NGINX only, not public
|
|
|
|
# Proxy to the /v1/auth/static URL on the web app.
|
|
# This line assumes the website runs on localhost:8080.
|
|
proxy_pass http://localhost:8080/v1/auth/static;
|
|
proxy_pass_request_body off;
|
|
proxy_set_header Content-Length "";
|
|
|
|
# Important: the X-Original-URI header tells the web app what the
|
|
# original path (e.g. /static/photos/*) was, so the web app knows
|
|
# which sub-URL to enforce authentication on.
|
|
proxy_set_header X-Original-URI $request_uri;
|
|
}
|
|
}
|
|
```
|
|
|
|
When your NGINX config is set up like the above, you can edit the
|
|
settings.json to mark SignedPhoto/Enabled=true, and restart the
|
|
website. Be sure to test it!
|
|
|
|
On a photo gallery view, all image URLs under /static/photos/ should
|
|
come with a ?jwt= parameter, and the image should load for the current
|
|
user. The JWT token is valid for 30 seconds after which the direct link
|
|
to the image should expire and give a 403 Forbidden response.
|
|
|
|
When this feature is NOT enabled/not enforcing: the jwt= parameter is
|
|
still generated on photo URLs but is not enforced by the web app.
|
|
|
|
## Usage
|
|
|
|
The `nonshy` binary has sub-commands to either run the web server
|
|
or perform maintenance tasks such as creating admin user accounts.
|
|
|
|
Run `nonshy --help` for its documentation.
|
|
|
|
Run `nonshy web` to start the web server.
|
|
|
|
```bash
|
|
nonshy web --host 0.0.0.0 --port 8080 --debug
|
|
```
|
|
|
|
## Create Admin User Accounts
|
|
|
|
Use the `nonshy user add` command like so:
|
|
|
|
```bash
|
|
$ nonshy user add --admin \
|
|
--email name@domain.com \
|
|
--password secret \
|
|
--username admin
|
|
```
|
|
|
|
Shorthand options `-e`, `-p` and `-u` can work in place of the longer
|
|
options `--email`, `--password` and `--username` respectively.
|
|
|
|
After the first admin user is created, you may promote other users thru
|
|
the web app by using the admin controls on their profile page.
|
|
|
|
## A Brief Tour of the Code
|
|
|
|
* `cmd/nonshy/main.go`: the entry point for the Go program.
|
|
* `pkg/webserver.go`: the entry point for the web server.
|
|
* `pkg/config`: mostly hard-coded configuration values - all of the page
|
|
sizes and business logic controls are in here, set at compile time. For
|
|
ease of local development you may want to toggle SkipEmailValidation in
|
|
here - the signup form will then directly allow full signup with a user
|
|
and password.
|
|
* `pkg/controller`: the various web endpoint controllers are here,
|
|
categorized into subpackages (account, forum, inbox, photo, etc.)
|
|
* `pkg/log`: the logging to terminal functions.
|
|
* `pkg/mail`: functions for delivering HTML email messages.
|
|
* `pkg/markdown`: functions to render GitHub Flavored Markdown.
|
|
* `pkg/middleware`: HTTP middleware functions, for things such as:
|
|
* Session cookies
|
|
* Authentication (LoginRequired, AdminRequired)
|
|
* CSRF protection
|
|
* Logging HTTP requests
|
|
* Panic recovery for unhandled server errors
|
|
* `pkg/models`: the SQL database models and query functions are here.
|
|
* `pkg/models/deletion`: the code to fully scrub wipe data for
|
|
user deletion (GDPR/CCPA compliance).
|
|
* `pkg/photo`: photo management functions: handle uploads, scale and
|
|
crop, generate URLs and deletion.
|
|
* `pkg/ratelimit`: rate limiter for login attempts etc.
|
|
* `pkg/redis`: Redis cache functions - get/set JSON values for things like
|
|
session cookie storage and temporary rate limits.
|
|
* `pkg/router`: the HTTP route URLs for the controllers are here.
|
|
* `pkg/session`: functions to read/write the user's session cookie
|
|
(log in/out, get current user, flash messages)
|
|
* `pkg/templates`: functions to handle HTTP responses - render HTML
|
|
templates, issue redirects, error pages, ...
|
|
* `pkg/utility`: miscellaneous useful functions for the app.
|
|
|
|
## Cron workers
|
|
|
|
You can schedule the `nonshy vacuum` command in your crontab. This command
|
|
will check and clean up the database for things such as: orphaned comment
|
|
photos (where somebody uploaded a photo to post on the forum, but then didn't
|
|
finish creating their post).
|
|
|
|
```cron
|
|
0 2 * * * cd /home/nonshy/git/website && ./nonshy vacuum
|
|
```
|
|
|
|
## License
|
|
|
|
GPLv3.
|