kind
Types and Extensibility
kind
Types
SeedPass is a secure password generator and manager
leveraging Bitcoin’s BIP-85 standard and integrating
with the Nostr network for decentralized
synchronization. Instead of pushing one large index file, SeedPass posts
snapshot chunks of the index followed by lightweight
delta events whenever changes occur. This chunked
approach improves reliability and keeps bandwidth usage minimal. To
enhance modularity, scalability, and security, SeedPass stores all
entries in a single encrypted index file named
seedpass_entries_db.json.enc
. This document outlines the
entry management system, ensuring that new kind
types can
be added seamlessly without disrupting existing functionalities.
All entries belonging to a seed profile are stored in an encrypted
file named seedpass_entries_db.json.enc
. This index uses
schema_version
3
and contains an
entries
object keyed by numeric identifiers.
{
"schema_version": 3,
"entries": {
"0": {
"label": "example.com",
"length": 8,
"username": "user",
"url": "https://example.com",
"archived": false,
"type": "password",
"kind": "password",
"notes": "",
"custom_fields": [],
"origin": ""
}
}
}
Each entry is stored within seedpass_entries_db.json.enc
under the entries
dictionary. The structure supports
diverse entry types (kind
) and allows for future
expansions.
{
"label": "Example",
"length": 8,
"username": "user@example.com",
"url": "https://example.com",
"archived": false,
"type": "password",
"kind": "password",
"notes": "",
"custom_fields": [],
"origin": "",
"tags": [],
"index": 0
}
label (string
): Descriptive name
for the entry (e.g., website or service).
length (integer
, optional): Desired
password length for generated passwords.
username (string
, optional):
Username associated with the entry.
url (string
, optional): Website or
service URL.
archived (boolean
): Marks the entry
as archived when true
.
type (string
): The entry type
(password
, totp
, ssh
,
seed
, pgp
, nostr
,
note
, key_value
).
kind (string
): Synonym for
type
kept for backward compatibility.
notes (string
): Free-form
notes.
custom_fields (array
, optional):
Additional user-defined fields.
origin (string
, optional): Source
identifier for imported data.
value (string
, optional): For
key_value
entries, stores the secret value.
index (integer
, optional): BIP-85
derivation index for entries that derive material from a seed.
word_count (integer
,
managed_account only): Number of words in the child seed. Managed
accounts always use 12
.
fingerprint (string
,
managed_account only): Identifier of the child profile, used for its
directory name.
tags (array
, optional): Category
labels to aid in organization and search. Example:
"custom_fields": [
{"name": "account_id", "value": "123"},
{"name": "recovery_hint", "value": "mother's maiden name"}
]
{
"entry_num": 0,
"index_num": 0,
"fingerprint": "a1b2c3d4",
"kind": "generated_password",
"data": {
"title": "Example Website",
"username": "user@example.com",
"email": "user@example.com",
"url": "https://example.com",
"password": "<encrypted_password>"
},
"custom_fields": [
{"name": "department", "value": "finance"}
],
"tags": ["work"],
"timestamp": "2024-04-27T12:34:56Z",
"metadata": {
"created_at": "2024-04-27T12:34:56Z",
"updated_at": "2024-04-27T12:34:56Z",
"checksum": "abc123def456"
}
}
{
"entry_num": 1,
"index_num": "q1wec4d426fs",
"fingerprint": "a1b2c3d4",
"kind": "stored_password",
"data": {
"title": "Another Service",
"username": "another_user",
"password": "<encrypted_password>"
},
"timestamp": "2024-04-27T12:35:56Z",
"metadata": {
"created_at": "2024-04-27T12:35:56Z",
"updated_at": "2024-04-27T12:35:56Z",
"checksum": "def789ghi012"
}
}
{
"entry_num": 2,
"index_num": "a1b2c3d4e5f6",
"fingerprint": "a1b2c3d4",
"kind": "managed_user",
"data": {
"users_password": "<encrypted_users_password>"
},
"timestamp": "2024-04-27T12:36:56Z",
"metadata": {
"created_at": "2024-04-27T12:36:56Z",
"updated_at": "2024-04-27T12:36:56Z",
"checksum": "ghi345jkl678"
}
}
{
"entry_num": 3,
"index_num": "f7g8h9i0j1k2",
"fingerprint": "a1b2c3d4",
"kind": "12_word_seed",
"data": {
"seed_phrase": "<encrypted_seed_phrase>"
},
"timestamp": "2024-04-27T12:37:56Z",
"metadata": {
"created_at": "2024-04-27T12:37:56Z",
"updated_at": "2024-04-27T12:37:56Z",
"checksum": "jkl901mno234"
}
}
{
"entry_num": 4,
"index_num": "l3m4n5o6p7q8",
"fingerprint": "a1b2c3d4",
"kind": "nostr_keys",
"data": {
"public_key": "<public_key>",
"private_key": "<encrypted_private_key>"
},
"timestamp": "2024-04-27T12:38:56Z",
"metadata": {
"created_at": "2024-04-27T12:38:56Z",
"updated_at": "2024-04-27T12:38:56Z",
"checksum": "mno567pqr890"
}
}
{
"entry_num": 5,
"index_num": "r9s0t1u2v3w4",
"fingerprint": "a1b2c3d4",
"kind": "note",
"data": {
"content": "This is a secure note.",
"tags": ["personal", "secure"]
},
"timestamp": "2024-04-27T12:39:56Z",
"metadata": {
"created_at": "2024-04-27T12:39:56Z",
"updated_at": "2024-04-27T12:39:56Z",
"checksum": "pqr345stu678"
}
}
{
"entry_num": 6,
"fingerprint": "a1b2c3d4",
"kind": "key_value",
"data": {
"key": "api_key",
"value": "<encrypted_value>"
},
"tags": ["api"],
"timestamp": "2024-04-27T12:40:56Z"
}
{
"entry_num": 7,
"fingerprint": "a1b2c3d4",
"kind": "managed_account",
"data": {
"account": "alice@example.com",
"password": "<encrypted_password>"
},
"timestamp": "2024-04-27T12:41:56Z"
}
Managed accounts store a child seed derived from the parent profile.
The entry is saved under
.seedpass/<parent_fp>/accounts/<child_fp>
where
<child_fp>
is the managed account’s fingerprint. When
loaded, the CLI displays a breadcrumb like
<parent_fp> > Managed Account > <child_fp>
.
Press Enter on the main menu to exit back to the parent
profile.
The key
field is purely descriptive, while
value
holds the sensitive string such as an API token.
Notes and custom fields may also be included alongside the standard
metadata.
kind
Types and ExtensibilityThe JSON schema is designed to be extensible and
forward-compatible, allowing new kind
types to be added without impacting existing functionalities.
Each entry is encapsulated in its own JSON file with a standardized structure:
{
"entry_num": 0,
"index_num": 0,
"fingerprint": "a1b2c3d4",
"kind": "generated_password",
"data": {
// Fields specific to the kind
},
"timestamp": "2024-04-27T12:34:56Z",
"metadata": {
"created_at": "2024-04-27T12:34:56Z",
"updated_at": "2024-04-27T12:34:56Z",
"checksum": "<checksum_value>"
}
}
kind
Fieldkind
values can be introduced without altering the existing
schema.Example:
"kind": "cryptocurrency_wallet"
data
Objectkind
.kind
can define
its unique set of fields without affecting others.Example for a New Kind
(cryptocurrency_wallet
):
"data": {
"wallet_name": "My Bitcoin Wallet",
"address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
"private_key": "<encrypted_private_key>"
}
To maintain compatibility as new kind
types are
introduced, implement the following practices:
kind
, handle it gracefully by ignoring the entry, logging a
warning, or providing a default handling mechanism.kind
types.Pseudo-Code Example:
def process_entry(entry):
= entry.get("kind")
kind = entry.get("data")
data = entry.get("fingerprint")
fingerprint
if kind == "generated_password":
handle_generated_password(data, fingerprint)elif kind == "stored_password":
handle_stored_password(data, fingerprint)# ... other known kinds ...
else:
f"Unknown kind: {kind}. Skipping entry.") log_warning(
schema_version
or seedpass_version
field to
indicate the version of the JSON schema being used.Example:
"seedpass_version": "1.0.0"
kind
, detailing required and
optional fields.kind
types.To ensure seamless integration of new kind
types in the
future, consider the following best practices:
kind
names do not clash with existing or future reserved keywords within the
application or JSON standards.kind
. Promotes code modularity
and easier maintenance.Example:
# handlers.py
def handle_generated_password(data, fingerprint):
# Implementation
def handle_stored_password(data, fingerprint):
# Implementation
def handle_cryptocurrency_wallet(data, fingerprint):
# Implementation
kind
has the necessary fields before processing.Example:
def handle_cryptocurrency_wallet(data, fingerprint):
= ["wallet_name", "address", "private_key"]
required_fields for field in required_fields:
if field not in data:
raise ValueError(f"Missing required field '{field}' in cryptocurrency_wallet entry.")
# Proceed with processing
kind
types.kind
TypesAdding new kind
types is straightforward due to the
extensible JSON schema design. Below is a step-by-step guide to adding a
new kind
without affecting existing functionalities.
cryptocurrency_wallet
Create a JSON file following the standardized structure with the new
kind
value.
{
"entry_num": 6,
"index_num": "x1y2z3a4b5c6",
"fingerprint": "a1b2c3d4",
"kind": "cryptocurrency_wallet",
"data": {
"wallet_name": "My Bitcoin Wallet",
"address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
"private_key": "<encrypted_private_key>"
},
"timestamp": "2024-04-27T12:40:56Z",
"metadata": {
"created_at": "2024-04-27T12:40:56Z",
"updated_at": "2024-04-27T12:40:56Z",
"checksum": "stu901vwx234"
}
}
Implement Handler Function:
def handle_cryptocurrency_wallet(data, fingerprint):
= data.get("wallet_name")
wallet_name = data.get("address")
address = decrypt(data.get("private_key"))
private_key # Process the cryptocurrency wallet entry
# e.g., store in memory, display to user, etc.
Integrate the Handler:
def process_entry(entry):
= entry.get("kind")
kind = entry.get("data")
data = entry.get("fingerprint")
fingerprint
if kind == "generated_password":
handle_generated_password(data, fingerprint)elif kind == "stored_password":
handle_stored_password(data, fingerprint)elif kind == "cryptocurrency_wallet":
handle_cryptocurrency_wallet(data, fingerprint)# ... other known kinds ...
else:
f"Unknown kind: {kind}. Skipping entry.") log_warning(
Existing kinds such as generated_password
,
stored_password
, etc., continue to operate without any
changes. The introduction of cryptocurrency_wallet
is
additive and does not interfere with the processing of other kinds.
To ensure data integrity and provide recovery options, SeedPass implements a robust backup and rollback system within the Fingerprint-Based Backup and Local Storage framework.
All backups are organized based on fingerprints, ensuring that each seed’s data remains isolated and secure.
~/.seedpass/
├── a1b2c3d4/
│ ├── entries/
│ │ ├── entry_0.json
│ │ ├── entry_1.json
│ │ └── ...
│ ├── backups/
│ │ ├── entry_0_v1.json
│ │ ├── entry_0_v2.json
│ │ ├── entry_1_v1.json
│ │ └── ...
│ ├── parent_seed.enc
│ ├── seedpass_entries_db_checksum.txt
│ └── seedpass_entries_db.json
├── b5c6d7e8/
│ ├── entries/
│ │ ├── entry_0.json
│ │ ├── entry_1.json
│ │ └── ...
│ ├── backups/
│ │ ├── entry_0_v1.json
│ │ ├── entry_0_v2.json
│ │ ├── entry_1_v1.json
│ │ └── ...
│ ├── parent_seed.enc
│ ├── seedpass_entries_db_checksum.txt
│ └── seedpass_entries_db.json
└── ...
backups/
directory within the corresponding fingerprint
folder with a version suffix (e.g., entry_0_v1.json
).entries/
directory
within the same fingerprint folder.backups/
directory within the specific fingerprint folder.entries/
directory, replacing the current version.Example Command:
seedpass rollback --fingerprint a1b2c3d4 --file entry_0_v1.json
Example Directory Structure After Rollback:
~/.seedpass/
├── a1b2c3d4/
│ ├── entries/
│ │ ├── entry_0.json # Restored from entry_0_v1.json
│ │ ├── entry_1.json
│ │ └── ...
│ ├── backups/
│ │ ├── entry_0_v1.json
│ │ ├── entry_0_v2.json
│ │ ├── entry_1_v1.json
│ │ └── ...
│ ├── parent_seed.enc
│ ├── seedpass_script_checksum.txt
│ ├── seedpass_entries_db_checksum.txt
│ └── seedpass_entries_db.json
├── ...
Note: Restoring a backup overwrites the current entry. Ensure that you intend to revert to the selected backup before proceeding.