# webjrnl
minimal HTML4 journalling program, written in golang
features:
- filesystem database
- javascript-free
- you can probably use this on anything with a TCP stack
- versioning system
I wrote this so I could edit my journal (a text file) from multiple
computers. it is basically a system for versioning and editing sections
of a specially-formatted text file
## installing
```
$ git clone https://git.amehut.dev/~aleteoryx/webjrnl
$ cd webjrnl
$ go build -ldflags '-w -s'
$ mkdir db
$ echo -n 'changeme' | sha1sum
fa9beb99e4029ad5a6615399e7bbae21356086b3 -
$ echo '[{"id": "marmalade", "passhash": "fa9beb99e4029ad5a6615399e7bbae21356086b3"}]' >db/users.json
$ ./jrnl :8080 db
initialized!
```
this is untested in go versions < 1.24.5. if you successfuly compile it
in an earlier version, let me know and I will update go.mod. it has
been tested on linux, but should have no problems running on other
unixes, plan 9, or even windows.
webjrnl is a single executable, jrnl. it takes 2 arguments: the address
on which to listen, and the database location. if the second argument
is omitted, it is assumed to be `.`
if you plan to run webjrnl behind a reverse proxy, pass it the -proxied
flag. this will tell it to read the X-Forwarded-For header when writing
logs.
the database has the following layout:
```
db/
users.json - the list of users
{userid}/{year}/{month}/{day}/ - the entry for a given date
latest - contains the ID of the latest edit, in base 10
{id} - the full text of edit id
```
users.json contains an array, each element of which corresponds to a
jrnl. it must contain id and passhash. the former is the jrnl username,
the latter is the SHA-1 hash of the user's password. it may also
contain a timezone field, the value of which should be an IANA time
zone name, like "UTC" or "America/New_York". this timezone is used when
displaying dates in the UI.
users.json is read once, at startup. if you modify it, you will need to
restart the service.
no caching of the database is performed. for a performant experience,
make sure your kernel is configured to cache the database directory in
RAM.
webjrnl is written in such a way that multiple instances can be pointed
to the same database, and access it concurrently without risk of
corruption.
for convenience, an openrc script is included at /openrc. edit it to
your needs.
## usage
jrnl text is mostly free-form ASCII text, delimited by lines of the
form `> YYYY-MM-DD`. in any text box accepting jrnl text, you may
insert such a line anywhere to start a new entry. webjrnl will sort it
into reverse chronological order, once it is submitted.
webjrnl does not delete anything. when an entry is edited, the new text
is saved as the latest revision. it is not possible to delete an entry
or revision, without hand-editing the database.
a typical jrnl excerpt looks something like:
```
> 2026-04-26
= 1725, cafe =
got webjrnl mostly together, just need to write the docs.
...
> 2026-04-25
= 1020, desk =
I'm SO EXCITED for today!!!
...
```
the homepage, /dash, has links to a list of entries, an import tool, a
backup tool, and each year's page. if there is no entry for today or
yesterday, buttons to create them are also presented.
the import tool accepts jrnl text, and populates the database with it.
the backup tool exports the entire database as jrnl text, including all
revisions. it can be accessed programatically at /save?download
year pages are populated with the jrnl text for a given year, and have
a menu to navigate to an entry's page. this is intended as the primary
editing frontend.
entry pages allow you to change an entry's text, and contain a list of
previous revisions. this is not jrnl text, and does not parse date
headings. if you include one, it may lead to unexpected results the
next time the entry is parsed as part of jrnl text
## security
some. in particular, POST requests from a different Referer or Origin
are blocked, as are all javascript requests from different sites,
assuming the browser supports the `Sec-Fetch-*` set of headers
HTTP basic authentication is very much so insecure over an unencrypted
connection.
the contents of the database are stored in plaintext.
## compatibility
needs testing:
- netscape (the real one, not the chrome reskin)
- netpositive
- kaios
- wii browser channel
works, no notes:
- any modern web browser probably. works in librewolf
- lynx
- w3m
- MSIE 6
- k-meleon
- eww (thanks d6!)
- epiphany
works with caveats:
- links2: textareas start scrolled to the bottom, so the year pages are
a bit annoying.
- netsurf: textareas with a lot of data in them are laggy to edit, so
the year pages are annoying to work with
- plan 9 mothra: textareas are buggy, which makes any editing besides
entry creation a chore
- wine internet explorer: 401s aren't handled; you need to manually add
the user:pass@ to the URL. navigating with the back button breaks
this
- dillo: some weird caching behavior that requires manual reloads at
times, ignores content-disposition on /save
doesn't work:
- offpunk: no <form> support