cmd/nonshy | ||
docs | ||
pkg | ||
web | ||
.gitignore | ||
CONTRIBUTING.md | ||
go.mod | ||
go.sum | ||
LICENSE | ||
Makefile | ||
README.md |
nonshy website
This is the source code to the main 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 server. See the CONTRIBUTING.md file for details.
Dependencies
You may need to run the following services along with this app:
- A Redis cache server: redis.io
- (Optional) a PostgreSQL database: 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. You can probably get it from your package manager, e.g.
- macOS:
brew install golang
with homebrew: 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 dependenciesmake build
: builds the program to ./nonshymake 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):
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:
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.
nonshy web --host 0.0.0.0 --port 8080 --debug
Create Admin User Accounts
Use the nonshy user add
command like so:
$ 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).
0 2 * * * cd /home/nonshy/git/website && ./nonshy vacuum
License
GPLv3.