site

files for beauhilton.com
git clone https://git.beauhilton.com/site.git
Log | Files | Refs

commit ed475b8e7231c01f37b9122abc361bdffc1fb167
parent 14a58714d68ef5338ce66b753ac6e7f52c283c19
Author: Beau <cbeauhilton@gmail.com>
Date:   Thu, 12 Jan 2023 15:02:12 -0600

update

Diffstat:
Mindex.json | 10++++++++++
Asite/posts/pagecrypt.md | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/index.json b/index.json @@ -1,5 +1,15 @@ [ { + "url": "/posts/pagecrypt", + "page_file": "site/posts/pagecrypt.md", + "nav_path": [ + "posts" + ], + "excerpt": "Static site generators, by and large, do not have support for password protecting individual pages. \nThis post shows a strategy that works for any SSG, that does not require server access controls.", + "date": "2023-01-12", + "title": "password protecting static web pages" + }, + { "url": "/posts/oo-et-al", "page_file": "site/posts/oo-et-al.md", "nav_path": [ diff --git a/site/posts/pagecrypt.md b/site/posts/pagecrypt.md @@ -0,0 +1,102 @@ +# password protecting static web pages + +<time id="post-date">2023-01-12</time> + +<p id="post-excerpt"> +Static site generators, by and large, do not have support for password protecting individual pages. +This post shows a strategy that works for any SSG, that does not require server access controls. +</p> + +[PageCrypt](https://github.com/Greenheart/pagecrypt) is the tool I went with. +It's a TypeScript library that uses the native `Web Crypto API` to encrypt html pages, +stuff the encrypted gobbledigook behind a simple password form, +and decrypt the page when the correct key is given. + +I'm using the CLI version, but there are also native TypeScript and Node.js versions. + +The basic idea is this, taken from their docs: + +```sh +npx pagecrypt <src> <dest> [password] [options] +``` + +Below is an excerpt from a `package.json` for a Hugo site I maintain. +First I build the site, then run the `postbuild` command, +which stitches together a piece of code that creates a list of all the pages we'd like to encrypt +and another bit that does the encryption proper. + +## give me the code already + +```json + +{ + "make-pw-files-file": "grep -rlF 'password_required: true' content | sed s+\\.md+\\/index.html+g | sed s+content/+public/+g > pw_file", + "protect-files": "cat pw_file | while read f || [[ -n $f ]]; do npx pagecrypt $f $f $PAGECRYPT; done", + "postbuild": "npm run -s make-pw-files-file && npm run -s protect-files ", +} + +``` + +## ok, so how does it work? + +### `make-pw-files-file` + +This part uses a few standard Unix commands, the ubiquitous `grep` and `sed`. + +First it creates a list of markdown source files that have the header `password_required: true`. + +Here's how that part works: + +`grep -rlF "text you're looking for" path/to/files/of/interest` : + +- `-r` or `--recursive` searches though the sub-directories of whichever path you gave it +- `l` or `--files-with-matches` prints the filenames of any files that match the search +- `F` or `--fixed-strings` searches for the exact string you ask for, not using regular expressions + +This will output something like: + +`sh +content/file.md +content/file7.md +content/yet_another_file.md +` + +Next it passes that to `sed`, which replaces `.md` with `/index.html`\* +resulting in: + +`sh +content/file/index.html +content/file7/index.html +content/yet_another_file/index.html +` + +\* you'd have to adjust this command if you aren't using a page-per-folder style + +Then it switches out `content/` with `public/`, leading to the final list: + + +`sh +public/file/index.html +public/file7/index.html +public/yet_another_file/index.html +` + +and sends those to a file. + +Sending the list to a file is not necessary, +could just pipe it again to the stuff in `protect-files`, +but I was getting itchy at how long the command was getting. + +### `protect-files` + +This part emits the contents of `pw_file`, +then loops through each line (`while read f || [[ -n $f ]]`) +and encrypts the corresponding file (`do npx pagecrypt`), +saving it back to itself (`$f $f`). + +`$PAGECRYPT` is an environment variable that specifies the password. +You could also set a password-per-page, +either auto-generated (but you'd have to figure out how to get that password to your users), +or using something like another header value in the `.md` files that you grep for and save somewhere. +For my use case this is simpler and scales easily. +