Skip to content
Merged
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ 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).

## [0.0.11] - 2026-09-25

### Fixed

- **sidestr records are read by their push length.** The vendored spec lib moves
from `373d3eb` to `@sidestr/spec` 0.0.6 (`fa86dac`), whose `recordText`
compares a push's declared length with its data again (sidestr/spec#17): a
script that pushed `tal` with `ly:x` after the push read as the record
`tally:x`. The spend window's asset view and record display now read records
exactly as validators do. Only `records.mjs` changed in Podkey's vendored set.

## [0.0.10] - 2026-09-25

### Changed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> Browser extension for **did:nostr** and **Solid** authentication

[![Version](https://img.shields.io/badge/version-0.0.10-blue.svg)](https://github.com/JavaScriptSolidServer/podkey/actions/workflows/ci.yml?query=branch%3Amain+is%3Asuccess)
[![Version](https://img.shields.io/badge/version-0.0.11-blue.svg)](https://github.com/JavaScriptSolidServer/podkey/actions/workflows/ci.yml?query=branch%3Amain+is%3Asuccess)
[![License](https://img.shields.io/badge/license-AGPL--3.0-green.svg)](LICENSE)
[![NIP-07](https://img.shields.io/badge/NIP--07-compatible-purple.svg)](https://github.com/nostr-protocol/nips/blob/master/07.md)
[![Test Page](https://img.shields.io/badge/test--page-live-brightgreen)](https://javascriptsolidserver.github.io/podkey/test-page/)
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Podkey",
"version": "0.0.10",
"version": "0.0.11",
"description": "Nostr (NIP-07) signer and Solid (NIP-98) login. One did:nostr key, encrypted on your device.",
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "podkey",
"version": "0.0.10",
"version": "0.0.11",
"description": "did:nostr and Solid authentication extension - NIP-07 provider for decentralized identity",
"main": "src/index.js",
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion scripts/vendor-sidestr.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const PINS = [
{
name: 'spec',
repo: 'https://github.com/sidestr/spec',
commit: '373d3eb6accd163f418e8a813052f1516a942bb3',
commit: 'fa86dac83d47b8f70195132e91e9dc083e1d9228',
// what explorer.mjs imports from `${sidestr}`, plus what the spend window uses
entries: ['siding/lib/parents.mjs', 'siding/lib/overlay.mjs', 'siding/lib/overlays/index.mjs', 'siding/lib/txsign.mjs', 'siding/lib/announce.mjs', 'siding/lib/records.mjs', 'siding/lib/overlays/assets.mjs'],
documents: [],
Expand Down
8 changes: 8 additions & 0 deletions test/sidestr-vendor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,12 @@ describe('vendored sidestr engine', () => {
const { evmOverlay } = await import('../vendor/sidestr/spec/siding/lib/overlays/evm.mjs');
assert.throws(() => evmOverlay({ id: 'sidestr:x' }), (e) => e.code === 'unsupported');
});

it('the vendored records reader refuses a push whose length is not its data (sidestr/spec#17)', async () => {
const { recordText } = await import('../vendor/sidestr/spec/siding/lib/records.mjs');
const hx = (t) => Buffer.from(t).toString('hex');
assert.equal(recordText('6a03' + hx('tally:x')), null, 'bytes after the push');
assert.equal(recordText('6a07' + hx('abc')), null, 'bytes missing');
assert.equal(recordText('6a07' + hx('tally:x')), 'tally:x');
});
});
4 changes: 2 additions & 2 deletions vendor/sidestr/PINS.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
{
"name": "spec",
"repo": "https://github.com/sidestr/spec",
"commit": "373d3eb6accd163f418e8a813052f1516a942bb3",
"commit": "fa86dac83d47b8f70195132e91e9dc083e1d9228",
"files": {
"siding/lib/announce.mjs": "67a4e18d13eaa234fb4e9ddb5c3a275140fb33055e60e1d4150e4b0f23b12862",
"siding/lib/block.mjs": "3f9de6866080ff788aab6e898be7744c12988636f9137ec1eeddcfa66d57ca48",
Expand All @@ -44,7 +44,7 @@
"siding/lib/overlays/index.mjs": "58cccd190238b349c6f7815aefe1e2c4a337e8e770b060e06710824e8700f834",
"siding/lib/overlays/pool.mjs": "c86584bac7f4ff9c6af41f76dd6abd52c0a9e49bce23c9a5df218729377a0f04",
"siding/lib/parents.mjs": "a5e697a61e25c32a0df66def2809bac284247c777d5fa32647c08cfd249548ca",
"siding/lib/records.mjs": "8afa474cf154d8db6442a269deb30a83e67e8cc36e295c03c47a67c0c934ccca",
"siding/lib/records.mjs": "d314c419637122c450e3b3f1980d58c2837ed5e6b3b0e5d9b1751371ae3f2c51",
"siding/lib/txsign.mjs": "5f2af06056e30e6c0997c917ba05bfcce305b947a80df1c242a6b04931039875",
"LICENSE": "0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0"
},
Expand Down
3 changes: 2 additions & 1 deletion vendor/sidestr/spec/siding/lib/records.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ export const MAX_AMOUNT = 2 ** 53 - 1;
// the text of an OP_RETURN output, or null when it is not a single push of <= 255 bytes of UTF-8
export function recordText(spk) {
const m = /^6a(?:4c([0-9a-f]{2})|([0-9a-f]{2}))([0-9a-f]*)$/i.exec(spk); if (!m) return null;
const len = parseInt(m[1] ?? m[2], 16); if (m[2] && len > 75) return null; if (m[1] && len <= 75) return null; // minimal push only if (m[3].length !== len * 2 || len > 255) return null;
const len = parseInt(m[1] ?? m[2], 16); if (m[2] && len > 75) return null; if (m[1] && len <= 75) return null; // minimal push only
if (m[3].length !== len * 2 || len > 255) return null; // exactly the pushed bytes: nothing after the push, nothing missing
try { return dec.decode(Uint8Array.from(m[3].match(/../g) ?? [], (x) => parseInt(x, 16))); } catch { return null; }
}
export function recordScript(text) { const b = enc.encode(text); if (b.length > 255) throw new Error('a record is at most 255 bytes'); return '6a' + (b.length <= 75 ? b.length.toString(16).padStart(2, '0') : '4c' + b.length.toString(16).padStart(2, '0')) + toHex(b); }
Expand Down
Loading