Compare commits

...

6 commits

Author SHA1 Message Date
xeruf
0de4e2e55d fix(nostr_users): only keep latest user metadata 2025-01-23 15:25:56 +01:00
xeruf
3ed60c3457 feat(main): allow setting active key with MOSTR_ID 2025-01-23 15:23:35 +01:00
xeruf
7acdede38c fix(nostr_users): don't attach key to username
Somehow filtering consistently shows all tasks of same-named users anyways
2025-01-23 15:00:40 +01:00
xeruf
8c1902c1d3 enhance: sort users by newest first for name matching 2025-01-23 14:59:26 +01:00
xeruf
942e2fca75 docs(readme): some cli hints 2025-01-23 10:18:52 +01:00
xeruf
0d11c0a361 feat(main): use nip49 encryption for export and import and document migration 2025-01-22 15:18:40 +01:00
6 changed files with 346 additions and 180 deletions

422
Cargo.lock generated
View file

@ -38,21 +38,6 @@ dependencies = [
"cpufeatures",
]
[[package]]
name = "aes-gcm-siv"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d"
dependencies = [
"aead",
"aes",
"cipher",
"ctr",
"polyval",
"subtle",
"zeroize",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
@ -127,18 +112,6 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anyhow"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]]
name = "arrayref"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
[[package]]
name = "arrayvec"
version = "0.7.6"
@ -338,12 +311,6 @@ dependencies = [
"bitcoin_hashes 0.14.0",
]
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.1"
@ -369,12 +336,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
[[package]]
name = "bincode"
version = "1.3.3"
name = "bindgen"
version = "0.69.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
dependencies = [
"serde",
"bitflags 2.8.0",
"cexpr",
"clang-sys",
"itertools",
"lazy_static",
"lazycell",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
"which",
]
[[package]]
@ -458,23 +439,18 @@ dependencies = [
"serde",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "blake2b_simd"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780"
dependencies = [
"arrayref",
"arrayvec",
"constant_time_eq",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
@ -542,6 +518,15 @@ dependencies = [
"shlex",
]
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -603,6 +588,17 @@ dependencies = [
"zeroize",
]
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "clipboard-win"
version = "5.4.0"
@ -648,12 +644,6 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "constant_time_eq"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
[[package]]
name = "core-foundation"
version = "0.9.4"
@ -706,15 +696,6 @@ dependencies = [
"typenum",
]
[[package]]
name = "ctr"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
dependencies = [
"cipher",
]
[[package]]
name = "data-encoding"
version = "2.7.0"
@ -916,15 +897,13 @@ dependencies = [
]
[[package]]
name = "filetime"
version = "0.2.25"
name = "flatbuffers"
version = "23.5.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
checksum = "4dac53e22462d78c16d64a1cd22371b54cc3fe94aa15e7886a2fa6e5d1ab8640"
dependencies = [
"cfg-if",
"libc",
"libredox",
"windows-sys 0.59.0",
"bitflags 1.3.2",
"rustc_version",
]
[[package]]
@ -950,6 +929,7 @@ checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
@ -972,6 +952,17 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-executor"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.31"
@ -1061,6 +1052,12 @@ version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "gloo-timers"
version = "0.3.0"
@ -1419,6 +1416,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.169"
@ -1434,15 +1437,24 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "libloading"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets 0.52.6",
]
[[package]]
name = "libredox"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags",
"bitflags 2.8.0",
"libc",
"redox_syscall",
]
[[package]]
@ -1451,7 +1463,7 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e"
dependencies = [
"bitflags",
"bitflags 2.8.0",
"libc",
]
@ -1521,6 +1533,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.8.3"
@ -1543,9 +1561,8 @@ dependencies = [
[[package]]
name = "mostr"
version = "0.9.0"
version = "0.9.1"
dependencies = [
"base64 0.22.1",
"chrono",
"colog",
"colored",
@ -1560,7 +1577,6 @@ dependencies = [
"parse_datetime",
"regex",
"rustyline",
"simple_crypt",
"tokio",
"whoami",
]
@ -1592,13 +1608,23 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags",
"bitflags 2.8.0",
"cfg-if",
"cfg_aliases",
"libc",
"memoffset",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "nostr"
version = "0.38.0"
@ -1606,7 +1632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af7c1eebe17dd785e52e1f81149c1b50fa6ec92e4ac239840934d1ffbd4f631c"
dependencies = [
"async-trait",
"base64 0.22.1",
"base64",
"bech32",
"bip39",
"bitcoin",
@ -1636,6 +1662,18 @@ dependencies = [
"tokio",
]
[[package]]
name = "nostr-ndb"
version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71ed34e13a40732e57205e319f71f8c7f723b1c9ddaae4b714b5b428e6ccbde9"
dependencies = [
"async-trait",
"nostr",
"nostr-database",
"nostrdb",
]
[[package]]
name = "nostr-relay-pool"
version = "0.38.0"
@ -1662,11 +1700,39 @@ dependencies = [
"async-utility",
"nostr",
"nostr-database",
"nostr-ndb",
"nostr-relay-pool",
"tokio",
"tracing",
]
[[package]]
name = "nostrdb"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775484658a10d646c5e835fb9132a7528d1bf546a791d1176b052f1be69c04b2"
dependencies = [
"bindgen",
"cc",
"flatbuffers",
"futures",
"libc",
"thiserror 2.0.11",
"tokio",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "num"
version = "0.4.3"
@ -1777,6 +1843,12 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "parking"
version = "2.2.1"
@ -1875,18 +1947,6 @@ dependencies = [
"universal-hash",
]
[[package]]
name = "polyval"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
dependencies = [
"cfg-if",
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]]
name = "ppv-lite86"
version = "0.2.20"
@ -1896,6 +1956,16 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "prettyplease"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro-crate"
version = "3.2.0"
@ -1969,7 +2039,7 @@ version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [
"bitflags",
"bitflags 2.8.0",
]
[[package]]
@ -1980,7 +2050,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom",
"libredox",
"thiserror",
"thiserror 1.0.69",
]
[[package]]
@ -2027,31 +2097,34 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rust-argon2"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5885493fdf0be6cdff808d1533ce878d21cfa49c7086fa00c66355cd9141bfc"
dependencies = [
"base64 0.21.7",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "0.38.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
dependencies = [
"bitflags",
"bitflags 2.8.0",
"errno",
"libc",
"linux-raw-sys",
@ -2100,7 +2173,7 @@ name = "rustyline"
version = "15.0.0"
source = "git+https://github.com/xeruf/rustyline?rev=5364854#53648543f7511fb5271afed3748f2b08cc9810f3"
dependencies = [
"bitflags",
"bitflags 2.8.0",
"cfg-if",
"clipboard-win",
"fd-lock",
@ -2189,7 +2262,7 @@ version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
"bitflags",
"bitflags 2.8.0",
"core-foundation 0.9.4",
"core-foundation-sys",
"libc",
@ -2202,7 +2275,7 @@ version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316"
dependencies = [
"bitflags",
"bitflags 2.8.0",
"core-foundation 0.10.0",
"core-foundation-sys",
"libc",
@ -2219,6 +2292,12 @@ dependencies = [
"libc",
]
[[package]]
name = "semver"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
[[package]]
name = "serde"
version = "1.0.217"
@ -2285,6 +2364,15 @@ dependencies = [
"digest",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]]
name = "shlex"
version = "1.3.0"
@ -2300,22 +2388,6 @@ dependencies = [
"libc",
]
[[package]]
name = "simple_crypt"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19a335d088ffc07695a1aee7b94b72a70ba438bed139cf3f3397fcc6c102d113"
dependencies = [
"aes-gcm-siv",
"anyhow",
"bincode",
"log",
"rust-argon2",
"serde",
"serde_derive",
"tar",
]
[[package]]
name = "slab"
version = "0.4.9"
@ -2387,17 +2459,6 @@ dependencies = [
"syn",
]
[[package]]
name = "tar"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6"
dependencies = [
"filetime",
"libc",
"xattr",
]
[[package]]
name = "tempfile"
version = "3.15.0"
@ -2418,7 +2479,16 @@ version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
"thiserror-impl 1.0.69",
]
[[package]]
name = "thiserror"
version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
dependencies = [
"thiserror-impl 2.0.11",
]
[[package]]
@ -2432,6 +2502,27 @@ dependencies = [
"syn",
]
[[package]]
name = "thiserror-impl"
version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "tinystr"
version = "0.7.6"
@ -2502,7 +2593,7 @@ checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f"
dependencies = [
"either",
"futures-util",
"thiserror",
"thiserror 1.0.69",
"tokio",
]
@ -2568,6 +2659,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
dependencies = [
"nu-ansi-term",
"sharded-slab",
"smallvec",
"thread_local",
"tracing-core",
"tracing-log",
]
[[package]]
@ -2586,7 +2703,7 @@ dependencies = [
"rustls",
"rustls-pki-types",
"sha1",
"thiserror",
"thiserror 1.0.69",
"utf-8",
]
@ -2686,6 +2803,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "version_check"
version = "0.9.5"
@ -2794,6 +2917,18 @@ dependencies = [
"rustls-pki-types",
]
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
]
[[package]]
name = "whoami"
version = "1.5.2"
@ -3005,17 +3140,6 @@ version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
[[package]]
name = "xattr"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909"
dependencies = [
"libc",
"linux-raw-sys",
"rustix",
]
[[package]]
name = "xdg-home"
version = "1.3.0"

View file

@ -5,7 +5,7 @@ repository = "https://forge.ftt.gmbh/janek/mostr"
readme = "README.md"
license = "GPL 3.0"
authors = ["melonion"]
version = "0.9.0"
version = "0.9.1"
rust-version = "1.82"
edition = "2021"
default-run = "mostr"
@ -13,7 +13,7 @@ default-run = "mostr"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nostr-sdk = "0.38"
nostr-sdk = { version = "0.38", features = ["ndb", "nip49"] }
# Basics
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
regex = "1.11"
@ -29,8 +29,6 @@ directories = "5.0"
whoami = "1.5"
# slint = "1.8"
# Application Utils
base64 = "0.22"
simple_crypt = "0.2"
itertools = "0.12"
chrono = "0.4"
parse_datetime = "0.5"

View file

@ -12,7 +12,7 @@ An immutable nested collaborative task manager, powered by nostr!
Install rust(up) and run a development build with:
cargo run
cargo run -- ARGS
A `relay` list can be placed in a config file
under `${XDG_CONFIG_HOME:-$HOME/.config}/mostr/`.
@ -31,7 +31,30 @@ This one-liner can help you stay on the latest version
git pull && cargo install --path . && mostr
To exit the application, press `Ctrl-D`.
To exit mostr, press `Ctrl-D`.
### Migrating
All data is stored on the relay.
To use mostr on a new device,
the only thing needed is your private key.
To export your password-encrypted key,
run mostr with the `--export` flag on the previous machine,
optionally deleting the key from the system keystore.
You can then import a password-encrypted key
using the `--import` flag.
To change your keypair on an existing machine,
simply delete the current one through the `export` command
and rerun mostr.
There is no harm in using mostr from multiple devices,
though there may be delays in updates if it is used in parallel.
For best user experience,
exit mostr on a device when you are done
to ensure all changes are propagated.
## Reference

View file

@ -5,8 +5,6 @@ use crate::kinds::{format_tag_basic, match_event_tag, Prio, BASIC_KINDS, PROPERT
use crate::task::{State, StateChange, Task, MARKER_PROPERTY};
use crate::tasks::{referenced_event, PropertyCollection, StateFilter, TasksRelay};
use base64::prelude::BASE64_STANDARD;
use base64::Engine;
use chrono::{DateTime, Local, TimeZone, Utc};
use colored::Colorize;
use directories::ProjectDirs;
@ -23,7 +21,8 @@ use rustyline::config::Configurer;
use rustyline::error::ReadlineError;
use rustyline::DefaultEditor;
use std::collections::{HashMap, VecDeque};
use std::env::{args, var};
use std::env;
use std::env::{args};
use std::fs;
use std::fs::File;
use std::io::{BufRead, BufReader, Write};
@ -66,7 +65,7 @@ macro_rules! or_warn {
}
}
fn read_keys(keys_entry: Entry, readline: &mut DefaultEditor) -> Result<Keys> {
fn read_keys(keys_entry: &Entry, readline: &mut DefaultEditor) -> Result<Keys> {
if let Ok(pass) = keys_entry.get_secret() {
return Ok(SecretKey::from_slice(&pass).map(|s| Keys::new(s))
.inspect_err(|e| eprintln!("Invalid key in keychain: {e}"))?);
@ -149,31 +148,34 @@ async fn main() -> Result<()> {
.inspect(|_| { or_warn!(fs::remove_file(key_file)); }));
}
let keys_entry = Entry::new("mostr", "keys")?;
let keys_entry = Entry::new("mostr", &env::var("MOSTR_ID").unwrap_or("keys".to_string()))?;
let keys =
if args.peek().is_some_and(|arg| arg.trim_start_matches('-') == "import") {
let key = rl.readline("Enter your encrypted or plaintext secret key: ")?;
args.next();
let key = rl.readline("Enter your encrypted secret key: ")?;
let sanitized_key: String = key.chars().filter(|c| c.is_ascii_alphanumeric()).collect();
let encrypted_key = EncryptedSecretKey::from_bech32(&sanitized_key)?;
let mut guard = rl.set_cursor_visibility(false)?;
let enc_pwd = read_password(&mut rl, "Please enter the encryption password you used: ")?;
guard.take();
let data = simple_crypt::decrypt(&(BASE64_STANDARD.decode(key)?), enc_pwd.as_bytes())?;
let keys = Keys::new(SecretKey::from_slice(&data)?);
let keys = Keys::new(encrypted_key.to_secret_key(&enc_pwd)?);
if keys_entry.get_secret().is_err_and(|e| matches!(e, NoEntry)) ||
rl.readline(&format!("Override stored key with given keypair, public key: {} (y/n)? ", keys.public_key()))? == "y" {
keys_entry.set_secret(keys.secret_key().as_secret_bytes())?;
}
keys
} else {
read_keys(keys_entry, &mut rl)?
read_keys(&keys_entry, &mut rl)?
};
info!("My active public key: {}", keys.public_key());
if args.peek().is_some_and(|arg| arg.trim_start_matches('-') == "export") {
let enc_pwd = read_password(&mut rl, "Please enter an encryption password for your secret key: ")?;
let data = simple_crypt::encrypt(keys.secret_key().as_secret_bytes(), enc_pwd.as_bytes())?;
println!("Your encrypted key: {}", BASE64_STANDARD.encode(&data));
println!("Your encrypted key: {}", EncryptedSecretKey::new(keys.secret_key(), enc_pwd, 9, KeySecurity::Unknown)?.to_bech32()?);
if rl.readline("Do you want to erase your stored secret keys (y/n)? ")? == "y" {
keys_entry.delete_credential()?;
}
// TODO optionally delete
return Ok(());
}
@ -188,7 +190,7 @@ async fn main() -> Result<()> {
let relays_file = config_dir.join("relays");
// TODO use NewRelay message for all relays
match var("MOSTR_RELAY") {
match env::var("MOSTR_RELAY") {
Ok(relay) => {
or_warn!(client.add_relay(relay).await);
}

View file

@ -158,7 +158,7 @@ impl TasksRelay {
metadata: Option<Metadata>,
) -> Self {
let mut new = Self::with_sender(EventSender::from(url, tx, keys));
metadata.map(|m| new.users.insert(keys.public_key(), m));
metadata.map(|m| new.users.insert(keys.public_key(), m, Timestamp::now()));
new
}
@ -1228,7 +1228,7 @@ impl TasksRelay {
match event.kind {
Kind::GitIssue => self.add_task(event),
Kind::Metadata => match Metadata::from_json(event.content.as_str()) {
Ok(metadata) => { self.users.insert(event.pubkey, metadata); }
Ok(metadata) => { self.users.insert(event.pubkey, metadata, event.created_at); }
Err(e) => warn!("Cannot parse metadata: {} from {:?}", e, event),
},
Kind::Bookmarks => {

View file

@ -1,10 +1,13 @@
use nostr_sdk::{Keys, Metadata, PublicKey, Tag};
use itertools::Itertools;
use nostr_sdk::{Keys, Metadata, PublicKey, Tag, Timestamp};
use std::collections::HashMap;
use std::str::FromStr;
use log::debug;
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct NostrUsers {
users: HashMap<PublicKey, Metadata>,
user_times: HashMap<PublicKey, Timestamp>,
}
impl NostrUsers {
@ -23,11 +26,14 @@ impl NostrUsers {
if let Ok(key) = PublicKey::from_str(term) {
return self.users.get_key_value(&key);
}
self.users.iter().find(|(k, v)|
// TODO regex word boundary
v.name.as_ref().is_some_and(|n| n.to_ascii_lowercase().starts_with(term)) ||
v.display_name.as_ref().is_some_and(|n| n.to_ascii_lowercase().starts_with(term)) ||
(term.len() > 4 && k.to_string().starts_with(term)))
self.users.iter()
.sorted_unstable_by_key(|(k, v)| self.get_user_time(k))
.rev()
.find(|(k, v)|
// TODO regex word boundary
v.name.as_ref().is_some_and(|n| n.to_ascii_lowercase().starts_with(term)) ||
v.display_name.as_ref().is_some_and(|n| n.to_ascii_lowercase().starts_with(term)) ||
(term.len() > 4 && k.to_string().starts_with(term)))
}
pub(crate) fn get_displayname(&self, pubkey: &PublicKey) -> String {
@ -42,8 +48,21 @@ impl NostrUsers {
.unwrap_or_else(|| format!("{:.6}", pubkey.to_string()))
}
pub(super) fn insert(&mut self, pubkey: PublicKey, metadata: Metadata) {
self.users.insert(pubkey, metadata);
fn get_user_time(&self, pubkey: &PublicKey) -> u64 {
match self.user_times.get(pubkey) {
Some(t) => t.as_u64(),
None => Timestamp::zero().as_u64(),
}
}
pub(super) fn insert(&mut self, pubkey: PublicKey, metadata: Metadata, timestamp: Timestamp) {
if self.get_user_time(&pubkey) < timestamp.as_u64() {
debug!("Inserting user metadata for {}", pubkey);
self.users.insert(pubkey, metadata);
self.user_times.insert(pubkey, timestamp);
} else {
debug!("Skipping older user metadata for {}", pubkey);
}
}
pub(super) fn create(&mut self, pubkey: PublicKey) {
@ -57,7 +76,7 @@ impl NostrUsers {
fn test_user_extract() {
let keys = Keys::generate();
let mut users = NostrUsers::default();
users.insert(keys.public_key, Metadata::new().display_name("Tester Jo"));
users.insert(keys.public_key, Metadata::new().display_name("Tester Jo"), Timestamp::now());
assert_eq!(crate::kinds::extract_tags("Hello @test", &users),
("Hello".to_string(), vec![Tag::public_key(keys.public_key)]));
}