Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d109a41
fix: remove duplicate fetch/XHR interception from content script
May 12, 2026
f7f3ff3
security: move private key from chrome.storage.local to chrome.storag…
May 12, 2026
d9667da
security: fix Solid server auto-trust hostname matching
May 12, 2026
69eaaca
security: remove NIP-98 signed event cache to prevent replay attacks
May 12, 2026
af55262
security: whitelist message types in content script relay
May 12, 2026
5534b20
security: implement signing approval popup to replace auto-approve
May 12, 2026
84829ec
feat: NIP-44 (v2) encrypt/decrypt for window.nostr
jjohare Jun 14, 2026
617482c
Merge fix/dedup-fetch-interception (#14): remove duplicate fetch/XHR …
jjohare Jun 14, 2026
0fc26a9
Merge security/encrypted-key-storage (#12): private key in session st…
jjohare Jun 14, 2026
15c1ec3
Merge security/signing-approval-ui (#20): real per-origin signing con…
jjohare Jun 14, 2026
e6e00e6
Merge security/whitelist-message-types (#19): validate page->bg messa…
jjohare Jun 14, 2026
0edf057
Merge security/fix-solid-server-matching (#17): exact-host Solid auto…
jjohare Jun 14, 2026
ec17d53
Merge security/remove-nip98-cache (#18): kill NIP-98 replay cache
jjohare Jun 14, 2026
11c018c
test: update storage mock for session/local split
jjohare Jun 14, 2026
865b166
Merge feat/nip44-support (#21): NIP-44 (v2) encrypt/decrypt for windo…
jjohare Jun 14, 2026
adf1912
fix(crypto): self-verify schnorr signature in signEvent before returning
jjohare Jun 14, 2026
19b545d
fix(provider): stop advertising unimplemented nip04 and getRelays
jjohare Jun 14, 2026
ae8a1f3
fix(nip98): fresh-token nonce, page-side body hash, redirect-aware re…
jjohare Jun 14, 2026
2f740cb
chore(lint): add minimal ESLint config for browser-extension ESM
jjohare Jun 14, 2026
5b6056e
ci: add build/test/lint gate for PRs and pushes to main
jjohare Jun 14, 2026
4bc9514
feat(popup): calm, trustworthy redesign of the main popup
jjohare Jun 14, 2026
b4f674e
feat(approve): trustworthy redesign of the signing-consent prompt
jjohare Jun 14, 2026
3f83e90
feat(test-page): polished install/test landing, CSP-clean
jjohare Jun 14, 2026
6e03bbc
test: consent gate + NIP-98 token freshness/exact-origin coverage
jjohare Jun 14, 2026
677b9df
test: signEvent self-verify guard + honest provider surface
jjohare Jun 14, 2026
56fc537
test: page-side body-hash + content-script message whitelist
jjohare Jun 14, 2026
11562f1
test: NIP-44 length-bound and key-isolation edges
jjohare Jun 14, 2026
b51760d
merge(ci): ESLint config + GitHub Actions build/test/lint gate
jjohare Jun 14, 2026
3fd5d8c
merge(test): expand suite 56->133 over secured behaviour
jjohare Jun 14, 2026
5d9af02
merge(ui): polished popup, consent prompt, and test page
jjohare Jun 14, 2026
7192a72
chore(lint): prefix unused args with _ and promote no-unused-vars to …
jjohare Jun 14, 2026
7002f30
fix(consent): default auto-sign OFF so first-run installs never silen…
jjohare Jun 14, 2026
fdab878
ci: package built extension as a downloadable artifact for sideloading
jjohare Jun 14, 2026
66e8eb7
fix(ci): use portable test glob (test/*.test.js)
jjohare Jun 14, 2026
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
41 changes: 41 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"root": true,
"env": {
"browser": true,
"webextensions": true,
"serviceworker": true,
"es2022": true
},
"parserOptions": {
"ecmaVersion": 2022,
"sourceType": "module"
},
"extends": "eslint:recommended",
"rules": {
"no-eval": "error",
"no-implied-eval": "error",
"no-undef": "error",
"no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
]
},
"ignorePatterns": [
"node_modules/",
"dist/",
"**/*.bundle.js"
],
"overrides": [
{
"files": ["test/**/*.js", "scripts/**/*.js"],
"env": {
"node": true,
"browser": false
}
}
]
}
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI

on:
pull_request:
push:
branches:
- main

permissions:
contents: read

jobs:
build-test-lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Test
run: npm test

- name: Lint
run: npm run lint

- name: Package extension (sideloadable unpacked zip)
run: |
mkdir -p dist
zip -r dist/podkey-extension.zip manifest.json src popup $([ -d icons ] && echo icons) -x '*.test.js'

- name: Upload extension artifact
uses: actions/upload-artifact@v4
with:
name: podkey-extension
path: dist/podkey-extension.zip
if-no-files-found: error
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ All notable changes to Podkey will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- **NIP-44 (v2) encryption** — `window.nostr.nip44.encrypt(pubkey, plaintext)`
and `window.nostr.nip44.decrypt(pubkey, ciphertext)`, enabling NIP-17 / NIP-59
gift-wrapped direct messages. Crypto runs in the background service worker
(the private key never reaches the page), reusing the existing message-passing
path. Implemented with `@noble/ciphers` (chacha20) + `@noble/hashes`
(hkdf/hmac/sha256) + `@noble/secp256k1` (ECDH). Verified against the official
NIP-44 spec test vectors.

## [0.0.7] - 2024-12-XX

### Changed
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
- ✅ **Key Generation** - Secure cryptographic key generation using `@noble/secp256k1`
- ✅ **Key Import** - Import existing 64-char hex private keys
- ✅ **Event Signing** - Sign Nostr events with Schnorr signatures
- ✅ **NIP-44 Encryption** - v2 `encrypt`/`decrypt` for NIP-17/NIP-59 gift-wrapped DMs (key never leaves the background)
- ✅ **Trust Management** - Per-origin permissions with auto-approval
- ✅ **Beautiful UI** - Soft gradients, smooth animations
- ✅ **64-char Hex Keys** - Proper did:nostr format compatibility
Expand Down Expand Up @@ -261,6 +262,19 @@ const signed = await window.nostr.signEvent({
})
```

### `window.nostr.nip44.encrypt(pubkey, plaintext)` / `window.nostr.nip44.decrypt(pubkey, ciphertext)`

NIP-44 (v2) encryption, used by NIP-17 / NIP-59 gift-wrapped direct messages.
The private key never leaves the background service worker — encryption is
performed there and only the resulting base64 payload (or decrypted plaintext)
crosses to the page, mirroring the existing signing message path.

```javascript
const peer = '<64-char hex pubkey>'
const payload = await window.nostr.nip44.encrypt(peer, 'hello')
const plaintext = await window.nostr.nip44.decrypt(peer, payload)
```

### `window.nostr.getRelays()`

Returns relay configuration (coming soon).
Expand Down
19 changes: 16 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"dev": "echo 'Load extension from chrome://extensions in developer mode'",
"build": "npm run bundle",
"bundle": "node scripts/bundle.js",
"test": "node --test test/**/*.test.js",
"test": "node --test test/*.test.js",
"lint": "eslint src/"
},
"keywords": [
Expand All @@ -34,6 +34,7 @@
},
"homepage": "https://github.com/JavaScriptSolidServer/podkey#readme",
"dependencies": {
"@noble/ciphers": "^2.2.0",
"@noble/hashes": "^1.3.3",
"@noble/secp256k1": "^3.0.0"
},
Expand All @@ -44,4 +45,4 @@
"engines": {
"node": ">=18.0.0"
}
}
}
Loading
Loading