commit 9453fa56ac1e71a634ac55335d0a9ff718e82957 Author: Ian Keane Date: Sun Nov 30 18:20:47 2025 -0500 Initial commit diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..febed87 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,710 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr 2.4.1", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "async-stream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +dependencies = [ + "async-stream-impl", + "futures-core", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "base-x" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bin" +version = "2.2.1" +dependencies = [ + "clap", + "once_cell", + "rand", + "rocket", + "rocket_dyn_templates", + "rust-embed", + "sha256", + "syntect", + "time 0.3.7", + "tree_magic", +] + +[[package]] +name = "binascii" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.5", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "memchr 2.4.1", +] + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "winapi 0.3.9", +] + +[[package]] +name = "chrono-tz" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58549f1842da3080ce63002102d5bc954c7bc843d4f47818e642abdc36253552" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db058d493fb2f65f41861bfed7e3fe6335264a9f0f92710cab5bdf01fef09069" +dependencies = [ + "parse-zoneinfo", + "phf", + "phf_codegen", +] + +[[package]] +name = "clap" +version = "3.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63edc3f163b3c71ec8aa23f9bd6070f77edbf3d1d198b164afa90ff00e4ec62" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1132dc3944b31c20dd8b906b3a9f0a5d0243e092d59171414969657ac6aa85" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "const_fn" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" + +[[package]] +name = "cookie" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" +dependencies = [ + "percent-encoding", + "time 0.2.27", + "version_check", +] + +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" +dependencies = [ + "cfg-if 1.0.0", + "lazy_static", +] + +[[package]] +name = "deunicode" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" + +[[package]] +name = "devise" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c7580b072f1c8476148f16e0a0d5dedddab787da98d86c5082c5e9ed8ab595" +dependencies = [ + "devise_codegen", + "devise_core", +] + +[[package]] +name = "devise_codegen" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "123c73e7a6e51b05c75fe1a1b2f4e241399ea5740ed810b0e3e6cacd9db5e7b2" +dependencies = [ + "devise_core", + "quote", +] + +[[package]] +name = "devise_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841ef46f4787d9097405cac4e70fb8644fc037b526e8c14054247c0263c400d0" +dependencies = [ + "bitflags", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.5", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "encoding_rs" +version = "0.8.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "figment" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790b4292c72618abbab50f787a477014fe15634f96291de45672ce46afe122df" +dependencies = [ + "atomic", + "pear", + "serde", + "toml", + "uncased", + "version_check", +] + +[[package]] +name = "filetime" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.10", + "winapi 0.3.9", +] + +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + +[[package]] +name = "flate2" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if 1.0.0", + "crc32fast", + "libc", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fsevent" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" +dependencies = [ + "bitflags", + "fsevent-sys", +] + +[[package]] +name = "fsevent-sys" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" +dependencies = [ + "libc", +] + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "futures" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" + +[[package]] +name = "futures-executor" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" + +[[package]] +name = "futures-macro" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" + +[[package]] +name = "futures-task" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" + +[[package]] +name = "futures-util" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr 2.4.1", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generator" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1d9279ca822891c1a4dae06d185612cf8fc6acfe5dff37781b41297811b12ee" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "winapi 0.3.9", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "globset" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "globwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +dependencies = [ + "bitflags", + "ignore", + "walkdir", +] + +[[package]] +name = "h2" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94 diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2b3643 --- /dev/null +++ b/README.md @@ -0,0 +1,435 @@ +# Bin Pastebin Nix Flake + +This flake provides a Nix package and NixOS module for [bin](https://github.com/wantguns/bin), a minimal pastebin service that accepts binary files like images and PDFs. + +## Features + +- **Minimal and fast**: Written in Rust using the Rocket framework +- **Binary file support**: Upload images, PDFs, and other binary files +- **Multiple clients**: Web UI, CLI, and Vim integration +- **Self-contained**: No external database required +- **Security hardened**: Systemd service with strict security policies +- **Nginx integration**: Built-in reverse proxy configuration with SSL support + +## Quick Start + +### Using the Flake in Your NixOS Configuration + +Add the flake to your `flake.nix` inputs: + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + bin-flake.url = "path:/path/to/this/flake"; + # Or from GitHub (once published): + # bin-flake.url = "github:yourusername/bin-flake"; + }; + + outputs = { self, nixpkgs, bin-flake, ... }: { + nixosConfigurations.yourhost = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + bin-flake.nixosModules.default + ./configuration.nix + ]; + }; + }; +} +``` + +### Basic Configuration + +In your NixOS configuration: + +```nix +{ + services.bin = { + enable = true; + port = 6162; + address = "127.0.0.1"; + }; +} +``` + +### Complete Configuration Example + +```nix +{ + services.bin = { + enable = true; + + # Network settings + address = "127.0.0.1"; + port = 6162; + openFirewall = false; # Set to true if not using nginx + + # Storage settings + uploadDir = "/var/lib/bin/upload"; + binaryUploadLimit = 100; # MiB + + # UI settings + clientDescription = true; # Show CLI client info on landing page + + # Custom environment variables + environmentFile = pkgs.writeText "bin-env" '' + BIN_LIMITS={form="16 MiB"} + BIN_WORKERS=8 + BIN_IDENT=false + BIN_KEEP_ALIVE=5 + BIN_LOG_LEVEL=normal + ''; + + # Nginx reverse proxy + nginx = { + enable = true; + domain = "paste.yourdomain.com"; + enableSSL = true; # Uses Let's Encrypt + }; + }; + + # Ensure nginx and ACME are configured + services.nginx.enable = true; + security.acme = { + acceptTerms = true; + defaults.email = "admin@yourdomain.com"; + }; +} +``` + +## Configuration Options + +### Core Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `enable` | bool | false | Whether to enable the bin service | +| `package` | package | bin | The bin package to use | +| `user` | string | "bin" | User account under which bin runs | +| `group` | string | "bin" | Group under which bin runs | + +### Network Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `address` | string | "127.0.0.1" | Address on which the webserver listens | +| `port` | int | 6162 | Port on which the webserver listens | +| `openFirewall` | bool | false | Whether to open the firewall for the service | + +### Storage Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `uploadDir` | path | "/var/lib/bin/upload" | Directory where uploaded pastes are stored | +| `binaryUploadLimit` | int | 100 | Binary uploads file size limit (in MiB) | + +### Feature Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `clientDescription` | bool | true | Whether to show the /client description on landing page | +| `extraArgs` | list of strings | [] | Extra command-line arguments to pass to bin | +| `environmentFile` | null or path | null | File containing environment variables for bin | + +### Nginx Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `nginx.enable` | bool | false | Whether to enable nginx reverse proxy | +| `nginx.domain` | string | "paste.example.com" | Domain name for the bin service | +| `nginx.enableSSL` | bool | true | Whether to enable SSL (uses ACME/Let's Encrypt) | + +## Environment Variables + +The bin service supports additional configuration through environment variables. You can set these using the `environmentFile` option: + +```nix +environmentFile = pkgs.writeText "bin-env" '' + # Rocket configuration + BIN_LIMITS={form="16 MiB"} # Form data size limit + BIN_WORKERS=8 # Number of worker threads + BIN_IDENT=false # Disable server identification + BIN_KEEP_ALIVE=5 # Keep-alive timeout in seconds + BIN_LOG_LEVEL=normal # Log level: off, critical, normal, debug + + # Additional Rocket settings + BIN_SECRET_KEY=your-secret-key # For encrypted cookies (generate with openssl) + BIN_TLS={certs="path/to/certs",key="path/to/key"} # TLS configuration +''; +``` + +## Client Configuration + +### Web Client + +Access the web interface at `http://localhost:6162` (or your configured domain). + +### CLI Client + +The CLI client can be installed and configured: + +```bash +# Download the client +curl -o ~/.local/bin/pst https://yourdomain.com/client +chmod +x ~/.local/bin/pst + +# Or create your own client script +cat > ~/.local/bin/pst << 'EOF' +#!/bin/bash +URL="https://paste.yourdomain.com" +FILEPATH="$1" +FILENAME=$(basename -- "$FILEPATH") +EXTENSION="${FILENAME##*.}" + +RESPONSE=$(curl --data-binary @${FILEPATH:-/dev/stdin} --url $URL) +PASTELINK="$URL$RESPONSE" + +[ -z "$EXTENSION" ] && \ + echo "$PASTELINK" || \ + echo "$PASTELINK.$EXTENSION" +EOF +chmod +x ~/.local/bin/pst +``` + +Usage: +```bash +# Upload a file +pst somefile.txt + +# Pipe content +echo "Hello, World!" | pst + +# Upload an image +pst screenshot.png +``` + +### Vim Integration + +Add to your `init.vim` or `.vimrc`: + +```vim +nnoremap p :!pst % +``` + +## Security Considerations + +The NixOS module implements several security measures: + +1. **Systemd Hardening**: The service runs with strict sandboxing +2. **Separate User**: Runs under a dedicated system user +3. **Filesystem Isolation**: Only the upload directory is writable +4. **Network Restrictions**: Limited to IPv4/IPv6 address families +5. **System Call Filtering**: Restricted to necessary system calls + +## Maintenance + +### Viewing Logs + +```bash +# View service logs +sudo journalctl -u bin -f + +# View nginx logs (if using reverse proxy) +sudo journalctl -u nginx -f +``` + +### Managing Uploads + +```bash +# View disk usage +du -sh /var/lib/bin/upload + +# Clean old uploads (example: files older than 30 days) +find /var/lib/bin/upload -type f -mtime +30 -delete + +# Backup uploads +tar -czf bin-uploads-$(date +%Y%m%d).tar.gz /var/lib/bin/upload +``` + +### Service Management + +```bash +# Restart the service +sudo systemctl restart bin + +# Check service status +sudo systemctl status bin + +# Reload after configuration changes +sudo nixos-rebuild switch +``` + +## Advanced Usage + +### Custom Nginx Configuration + +If you need more control over the nginx configuration: + +```nix +{ + services.bin = { + enable = true; + nginx.enable = false; # Disable automatic nginx config + }; + + services.nginx.virtualHosts."paste.yourdomain.com" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://127.0.0.1:6162"; + extraConfig = '' + client_max_body_size 100M; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Custom headers + proxy_set_header X-Custom-Header "value"; + + # Rate limiting + limit_req zone=paste burst=5 nodelay; + ''; + }; + }; +} +``` + +### Running Multiple Instances + +You can run multiple bin instances on different ports: + +```nix +{ + services.bin = { + enable = true; + port = 6162; + uploadDir = "/var/lib/bin/upload"; + }; + + # Second instance (requires manual systemd service) + systemd.services.bin-private = { + description = "Private bin instance"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.bin}/bin/bin --port 6163 --upload /var/lib/bin-private/upload"; + User = "bin-private"; + Group = "bin-private"; + StateDirectory = "bin-private"; + }; + }; + + users.users.bin-private = { + isSystemUser = true; + group = "bin-private"; + }; + users.groups.bin-private = {}; +} +``` + +### Integration with Monitoring + +Example Prometheus/Grafana integration: + +```nix +{ + services.prometheus = { + enable = true; + scrapeConfigs = [{ + job_name = "bin"; + static_configs = [{ + targets = [ "localhost:6162" ]; + }]; + }]; + }; + + services.grafana.provision.dashboards = [{ + options.path = ./dashboards; + # Add your bin dashboard JSON here + }]; +} +``` + +## Troubleshooting + +### Service Won't Start + +1. Check logs: `sudo journalctl -u bin -e` +2. Verify permissions: `ls -la /var/lib/bin` +3. Check port availability: `sudo ss -tlnp | grep 6162` + +### Upload Errors + +1. Check file size limits in configuration +2. Verify disk space: `df -h /var/lib/bin` +3. Check nginx client_max_body_size if using reverse proxy + +### SSL Certificate Issues + +1. Ensure domain points to your server +2. Check ACME logs: `sudo journalctl -u acme-paste.yourdomain.com` +3. Verify ports 80/443 are accessible + +## Development + +To work on the bin source code: + +```bash +# Enter development shell +nix develop + +# Run locally +cargo run -- --address 127.0.0.1 --port 6162 + +# Run tests +cargo test + +# Format code +cargo fmt + +# Lint +cargo clippy +``` + +## Building + +### Build the package + +```bash +# Build the bin package +nix build .#bin + +# Build the Docker image +nix build .#docker + +# Load Docker image +docker load < result +``` + +### Cross-compilation + +The flake supports cross-compilation: + +```bash +# Build for aarch64-linux on x86_64-linux +nix build .#packages.aarch64-linux.bin +``` + +## Contributing + +Contributions are welcome! Please: + +1. Fork the repository +2. Create a feature branch +3. Test your changes thoroughly +4. Submit a pull request + +## License + +This flake is provided under the same license as the bin project (LGPL-3.0). + +## Credits + +- Original bin project: https://github.com/wantguns/bin +- Based on Rocket framework: https://rocket.rs/ \ No newline at end of file diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..89df8e2 --- /dev/null +++ b/flake.nix @@ -0,0 +1,300 @@ +{ + description = "A minimal pastebin which also accepts binary files like Images, PDFs and ships multiple clients"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { self, nixpkgs, flake-utils, rust-overlay }: + flake-utils.lib.eachDefaultSystem (system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { + inherit system overlays; + }; + + rustToolchain = pkgs.rust-bin.stable.latest.default.override { + extensions = [ "rust-src" ]; + targets = [ "x86_64-unknown-linux-musl" "aarch64-unknown-linux-musl" ]; + }; + + in + { + packages = { + default = self.packages.${system}.bin; + + bin = pkgs.rustPlatform.buildRustPackage rec { + pname = "bin"; + version = "2.4.0"; + + src = pkgs.fetchFromGitHub { + owner = "wantguns"; + repo = "bin"; + rev = "v${version}"; + hash = "sha256-gUTDe9LPJ0Y2JLnbLv2FQaUjeNj6a1LQ3V5Z9SVnxkc="; + }; + + cargoHash = "sha256-2SiHrc0L9YiL2vLzKPnJ4BREPyeODJlLNReJPPpKlAE="; + + nativeBuildInputs = with pkgs; [ + pkg-config + ]; + + buildInputs = with pkgs; [ + openssl + ] ++ lib.optionals stdenv.isDarwin [ + darwin.apple_sdk.frameworks.Security + ]; + + # Enable optimizations + CARGO_BUILD_INCREMENTAL = "false"; + RUST_BACKTRACE = "full"; + + meta = with pkgs.lib; { + description = "A minimal pastebin which also accepts binary files"; + homepage = "https://github.com/wantguns/bin"; + license = licenses.lgpl3Only; + maintainers = []; + platforms = platforms.all; + }; + }; + + docker = pkgs.dockerTools.buildImage { + name = "bin"; + tag = "latest"; + created = "now"; + contents = [ self.packages.${system}.bin pkgs.cacert ]; + config = { + Cmd = [ "${self.packages.${system}.bin}/bin/bin" ]; + ExposedPorts = { + "6162/tcp" = {}; + }; + Env = [ + "BIN_ADDRESS=0.0.0.0" + "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" + ]; + WorkingDir = "/"; + Volumes = { + "/upload" = {}; + }; + }; + }; + }; + + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + rustToolchain + pkg-config + openssl + cargo-watch + rust-analyzer + clippy + rustfmt + ]; + + RUST_BACKTRACE = 1; + }; + }) // { + nixosModules = { + default = self.nixosModules.bin; + + bin = { config, lib, pkgs, ... }: + with lib; + let + cfg = config.services.bin; + in + { + options.services.bin = { + enable = mkEnableOption "bin pastebin service"; + + package = mkOption { + type = types.package; + default = self.packages.${pkgs.system}.bin; + defaultText = literalExpression "pkgs.bin"; + description = "The bin package to use"; + }; + + user = mkOption { + type = types.str; + default = "bin"; + description = "User under which bin runs"; + }; + + group = mkOption { + type = types.str; + default = "bin"; + description = "Group under which bin runs"; + }; + + address = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "Address on which the webserver runs"; + }; + + port = mkOption { + type = types.port; + default = 6162; + description = "Port on which the webserver runs"; + }; + + uploadDir = mkOption { + type = types.path; + default = "/var/lib/bin/upload"; + description = "Path to the uploads folder"; + }; + + binaryUploadLimit = mkOption { + type = types.int; + default = 100; + description = "Binary uploads file size limit (in MiB)"; + }; + + clientDescription = mkOption { + type = types.bool; + default = true; + description = "Include client description on landing page"; + }; + + extraArgs = mkOption { + type = types.listOf types.str; + default = []; + description = "Extra command-line arguments to pass to bin"; + }; + + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + File containing environment variables for bin. + Useful for setting Rocket-specific configurations. + ''; + example = literalExpression '' + pkgs.writeText "bin-env" ''' + BIN_LIMITS={form="16 MiB"} + BIN_WORKERS=8 + BIN_IDENT=false + ''' + ''; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = "Whether to open the firewall for the bin port"; + }; + + nginx = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable nginx reverse proxy for bin"; + }; + + domain = mkOption { + type = types.str; + default = "paste.example.com"; + description = "Domain name for the bin service"; + }; + + enableSSL = mkOption { + type = types.bool; + default = true; + description = "Whether to enable SSL (uses ACME/Let's Encrypt)"; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.bin = { + description = "bin pastebin service"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + ExecStart = '' + ${cfg.package}/bin/bin \ + --address ${cfg.address} \ + --port ${toString cfg.port} \ + --upload ${cfg.uploadDir} \ + --binary-upload-limit ${toString cfg.binaryUploadLimit} \ + ${optionalString cfg.clientDescription "--client-desc"} \ + ${concatStringsSep " " cfg.extraArgs} + ''; + Restart = "on-failure"; + RestartSec = 5; + StateDirectory = "bin"; + WorkingDirectory = "/var/lib/bin"; + EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile; + + # Security hardening + NoNewPrivileges = true; + PrivateTmp = true; + ProtectSystem = "strict"; + ProtectHome = true; + ReadWritePaths = [ cfg.uploadDir ]; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + LockPersonality = true; + RestrictRealtime = true; + SystemCallFilter = "@system-service"; + SystemCallErrorNumber = "EPERM"; + PrivateDevices = true; + RestrictNamespaces = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + }; + }; + + users.users = mkIf (cfg.user == "bin") { + bin = { + isSystemUser = true; + group = cfg.group; + home = "/var/lib/bin"; + createHome = true; + }; + }; + + users.groups = mkIf (cfg.group == "bin") { + bin = {}; + }; + + systemd.tmpfiles.rules = [ + "d ${cfg.uploadDir} 0755 ${cfg.user} ${cfg.group} -" + ]; + + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; + + services.nginx = mkIf cfg.nginx.enable { + enable = true; + virtualHosts.${cfg.nginx.domain} = { + forceSSL = cfg.nginx.enableSSL; + enableACME = cfg.nginx.enableSSL; + locations."/" = { + proxyPass = "http://${cfg.address}:${toString cfg.port}"; + proxyWebsockets = true; + extraConfig = '' + client_max_body_size ${toString cfg.binaryUploadLimit}M; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + ''; + }; + }; + }; + }; + }; + }; + }; +}