Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cdn/plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
"identifier": "dev.randombits.excalidraw",
"staticFiles": ["dist", "package.json"]
},
{
"identifier": "io.github.nickstruglia.keyfold",
"staticFiles": ["dist", "package.json"]
},
{
"identifier": "com.sncommunity.standard-blue-theme",
"staticFiles": ["dist", "package.json"]
Expand Down
21 changes: 21 additions & 0 deletions packages/io.github.nickstruglia.keyfold/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Nicholas Truglia

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
36 changes: 36 additions & 0 deletions packages/io.github.nickstruglia.keyfold/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Keyfold

A key manager for Standard Notes: crypto seed phrases and wallet keys, plus SSH and PGP keys, API tokens and recovery
codes. Each entry folds into a one-line card, secrets stay hidden until revealed, saved entries open locked against
accidental changes, seed phrases and keys are checked for typos (BIP39, Electrum, Monero and aezeed checksums,
Base58Check, Bech32, PGP armor), and an optional vault password encrypts the whole note again (AES-256-GCM,
PBKDF2-SHA256 with 600,000 iterations). Encrypted backup files open in a single-file offline viewer, without Standard
Notes, and restore into an empty Keyfold note.

Its Content Security Policy blocks every outgoing connection (`connect-src 'none'`), and scripts, images and fonts
from other sites. The only runtime dependency is Preact.

- Source, tests and documentation: https://github.com/nickstruglia/standard-notes-keyfold (MIT)
- This copy: version 1.0.31, built from commit [`77e7bd8`](https://github.com/nickstruglia/standard-notes-keyfold/commit/77e7bd8bac96194cc162e63c118a7ac24687e712)

## Why the files are prebuilt

This repository builds its packages on Node 16, and Keyfold's build (Vite 8) needs Node 20.19 or newer. So
`prebuilt/` holds the output of Keyfold's own build for this package's address, and `yarn build` checks every file
against `SHA256SUMS` before copying it to `dist/`.

## Rebuilding and comparing

With Node 22.12 or newer:

```sh
git clone https://github.com/nickstruglia/standard-notes-keyfold.git
cd standard-notes-keyfold
git checkout 77e7bd8bac96194cc162e63c118a7ac24687e712
npm ci --ignore-scripts
node scripts/directory-package.mjs 1.0.31
diff -r directory-package/io.github.nickstruglia.keyfold/prebuilt <this folder>/prebuilt
diff directory-package/io.github.nickstruglia.keyfold/SHA256SUMS <this folder>/SHA256SUMS
```

The script builds Keyfold for `https://standardnotes.github.io/plugins/cdn/dist/static/io.github.nickstruglia.keyfold/dist/` and writes this folder, with the same files byte for byte.
4 changes: 4 additions & 0 deletions packages/io.github.nickstruglia.keyfold/SHA256SUMS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
68c5e8303d6404139810f4922454a4b63147d7df30523db485de62aa30656417 assets/index-5lEe8QFz.js
0e0ccb766d5e6a479278c3c98865189e0f0bde69ae739d75a1d26470613de64c icon.svg
b3e4d9d442990d877b3a95de634c3c70c74e4fd93c0f0902ec77822dc5a13deb index.html
7a444a29f7d33c083f56424000729be5572e7b91db735bc67f2153fff7e4ea9c keyfold-viewer.html
37 changes: 37 additions & 0 deletions packages/io.github.nickstruglia.keyfold/build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copies the prebuilt files to dist/ after checking each one against SHA256SUMS.
// They are Keyfold's own build for this address; README.md says how to rebuild them.
import { createHash } from 'crypto'
import { copyFileSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync } from 'fs'
import { dirname, join, relative } from 'path'
import { fileURLToPath } from 'url'

const here = dirname(fileURLToPath(import.meta.url))
const prebuilt = join(here, 'prebuilt')
const dist = join(here, 'dist')

const walk = (dir) =>
readdirSync(dir).flatMap((name) => {
const path = join(dir, name)
return statSync(path).isDirectory() ? walk(path) : [relative(prebuilt, path).split('\\').join('/')]
})

const sums = new Map(
readFileSync(join(here, 'SHA256SUMS'), 'utf8')
.trim()
.split('\n')
.map((line) => {
const [hash, file] = line.split(' ')
return [file, hash]
}),
)
const files = walk(prebuilt).sort()
if (files.join('\n') !== [...sums.keys()].sort().join('\n')) throw new Error('prebuilt/ does not match SHA256SUMS')

rmSync(dist, { recursive: true, force: true })
for (const file of files) {
const hash = createHash('sha256').update(readFileSync(join(prebuilt, file))).digest('hex')
if (hash !== sums.get(file)) throw new Error(`${file} does not match SHA256SUMS`)
mkdirSync(dirname(join(dist, file)), { recursive: true })
copyFileSync(join(prebuilt, file), join(dist, file))
}
console.log(`Keyfold: ${files.length} files checked and copied to dist/`)
28 changes: 28 additions & 0 deletions packages/io.github.nickstruglia.keyfold/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "sn-keyfold",
"version": "1.0.31",
"private": true,
"description": "A key manager for Standard Notes: seed phrases, wallet, SSH and PGP keys, API tokens and recovery codes, in collapsible cards with hidden fields and checksum checks.",
"author": "Nicholas Truglia",
"license": "MIT",
"homepage": "https://github.com/nickstruglia/standard-notes-keyfold",
"repository": {
"type": "git",
"url": "https://github.com/standardnotes/plugins",
"directory": "packages/io.github.nickstruglia.keyfold"
},
"scripts": {
"build": "node build.mjs"
},
"sn": {
"name": "Keyfold",
"content_type": "SN|Component",
"area": "editor-editor",
"main": "dist/index.html",
"file_type": "json",
"interchangeable": false,
"marketing_url": "https://github.com/nickstruglia/standard-notes-keyfold",
"thumbnail_url": "https://standardnotes.github.io/plugins/cdn/dist/static/io.github.nickstruglia.keyfold/dist/icon.svg",
"showInGallery": true
}
}

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/io.github.nickstruglia.keyfold/prebuilt/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions packages/io.github.nickstruglia.keyfold/prebuilt/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!doctype html>
<html lang="en" class="theme-pending">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src https://standardnotes.github.io/plugins/cdn/dist/static/io.github.nickstruglia.keyfold/dist/ http://localhost:* http://127.0.0.1:* file:; style-src https://standardnotes.github.io/plugins/cdn/dist/static/io.github.nickstruglia.keyfold/dist/ 'unsafe-inline' https: data: http://localhost:* http://127.0.0.1:*; img-src data:; font-src data:; connect-src 'none'; frame-src 'none'; worker-src 'none'; manifest-src 'none'; form-action 'none'; base-uri 'none'; object-src 'none'" />
<meta name="referrer" content="no-referrer" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex" />
<title>Keyfold</title>
<link rel="icon" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2064%2064%22%3E%3Crect%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2214%22%20fill%3D%22%23086dd6%22%2F%3E%3Cpath%20d%3D%22M32%2012l16%206v12c0%2010-7%2016.5-16%2019-9-2.5-16-9-16-19V18Z%22%20fill%3D%22none%22%20stroke%3D%22%23fff%22%20stroke-width%3D%224%22%20stroke-linejoin%3D%22round%22%2F%3E%3Cpath%20d%3D%22M25%2031h14v10H25z%20M28%2031v-3a4%204%200%200%201%208%200v3%22%20fill%3D%22none%22%20stroke%3D%22%23fff%22%20stroke-width%3D%223%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E%0A" type="image/svg+xml" />
<script defer src="./assets/index-5lEe8QFz.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
512 changes: 512 additions & 0 deletions packages/io.github.nickstruglia.keyfold/prebuilt/keyfold-viewer.html

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -27769,6 +27769,12 @@ __metadata:
languageName: node
linkType: hard

"sn-keyfold@workspace:packages/io.github.nickstruglia.keyfold":
version: 0.0.0-use.local
resolution: "sn-keyfold@workspace:packages/io.github.nickstruglia.keyfold"
languageName: unknown
linkType: soft

"sn-stylekit@npm:2.0.19":
version: 2.0.19
resolution: "sn-stylekit@npm:2.0.19"
Expand Down