Open smondet opened 1 year ago
Cool! Added you to the README
the #… part, which the browser should never send to the server
Ah, very interesting bit of the spec I wasn't aware of!
Thank you for the suggestions! I've been tempted by a CLI generator as you suggested, but I can't expect my mom to learn how to use it ("easy enough for my mom to use" was one of my criteria for this project).
@smondet introduced me to hscrypt a few years back, and I riffed on it a bit at https://github.com/hscrypt:
@robinmoisson's staticrypt is also interesting "prior art"!
Pretty tangential, but two avenues for further work I've been thinking about:
<Encrypted>
React componentI'm still pretty interested in streamlining the DX around creating the plaintext and ciphertext sites, and letting them be fully functional web apps. I often have notebooks or visualizations with sensitive data that I'd like to share on an "anyone with the link can view" basis. @smondet's "password in the URL fragment" trick solves part of that, but integrating the site construction with common web-dev workflows seems useful, and I haven't seen it done.
To that end, I've been thinking about whether one could make a React component that encrypts part of a page, so that the un-decrypted landing page can have nice chrome and a familiar-looking "login" flow (though it would only accept a password, not a username).
Next.js has various hooks for rendering things differently on client and server, so I've been thinking about whether an interface like this is possible:
function MyApp() {
return <Layout>
<Nav … />
<Encrypted pswd={window.pswd} /* only set on server…? */ >
<table> {/* secret data! */} </table>
<Plot /* secret plots! */ />
</Encrypted>
</Layout>
}
In some cases, the components / HTML structure don't even need to be a secret, just the data; that may be even easier to support:
function MyApp({ encryptedData }) {
const [ decryptedData, setDecryptedData ] = useState(null)
return <Layout>
<Nav … />
<DecryptionForm encryptedData={encryptedData} onDecrypt={setDecryptedData} />
{decryptedData && <Plot data={decryptedData} />}
</Layout>
}
In this case encryptedData
would be generated out-of-band, using a CLI like hscrypt
's that Seb mentioned above, so I guess this flow is pretty possible today. It would be cool to offer a helper for doing it in next.js' getStaticProps
hook for a given page (which runs only server-side / at site-generation time):
export function getStaticProps() {
// Load secretData.json
const secretData = JSON.parse(fs.readFileSync("secretData.json", "utf-8"))
// Encrypt with the current Git SHA
const encryptionKey = require('child_process').execSync('git log -1 --format=%H', { encoding: 'utf-8' }).trim()
const encryptedData = encrypt(secretData, encryptionKey)
// Pass to page as `props`
return { props: { encryptedData } }
}
export default function MyApp({ encryptedData }) {
// same as previous `MyApp`
}
Then next build && next export
would be pretty CI/CD-ready…
A lot of my use cases would get published via GitHub Actions (e.g. from a private repo containing private data), so the encryption key could be a repo-level secret, or even derived from the commit SHA.
You could imagine a reusable GHA that would enable this kind of CI/CD:
on:
push:
branches:
- www
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm install && npm run build
- uses: mprimi/build-encrypted-static-site@v1
with:
src: <output dir from `npm run build` above>
dst: encrypted-build
- uses: JamesIves/github-pages-deploy-action@4.1.1
with:
folder: encrypted-build
Anyway, cool project, thanks for making it!
@ryan-williams Interesting ideas!
https://gitlab.com/smondet/hscrypt (Uses
gpg
for encryption andOpenPGP.js
for decryption)2 things that is has that are nice and could be suggestions:
#…
part, which the browser should never send to the server), you can pass document + password, over encrypted chat like Signal or Matrix.org for instance like this https://smondet.gitlab.io/hscrypt/hscrypt-test.html#test-pass-phrase.