├── .github └── workflows │ ├── lints.yml │ └── main.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-MIT ├── LICENSE-UNLICENSE ├── README.md └── src ├── api.rs ├── config.rs ├── crypto.rs ├── error.rs ├── lib.rs ├── logger.rs ├── main.rs ├── opts.rs ├── privatebin.rs ├── uniffi_custom_types.rs └── util.rs /.github/workflows/lints.yml: -------------------------------------------------------------------------------- 1 | name: CI:clippy+rustfmt 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | 9 | # Make sure CI fails on all warnings, including Clippy lints 10 | env: 11 | RUSTFLAGS: "-Dwarnings" 12 | 13 | jobs: 14 | linting: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - uses: actions-rs/toolchain@v1 21 | with: 22 | toolchain: nightly 23 | profile: minimal 24 | components: rustfmt, clippy 25 | 26 | - name: Run rust clippy 27 | run: | 28 | cargo clippy --all-targets --all-features 29 | 30 | - name: Run rust fmt 31 | run: | 32 | cargo fmt --check 33 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | create_release: 10 | name: Create release 11 | runs-on: ubuntu-latest 12 | outputs: 13 | upload_url: ${{ steps.create_release.outputs.upload_url }} 14 | pbcli_version: ${{ env.PBCLI_VERSION }} 15 | steps: 16 | - name: Retrieve Version 17 | shell: bash 18 | if: env.PBCLI_VERSION == '' 19 | run: | 20 | echo "PBCLI_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV 21 | echo "version is: ${{ env.PBCLI_VERSION }}" 22 | - name: Create release 23 | id: create_release 24 | uses: actions/create-release@v1 25 | env: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | with: 28 | tag_name: ${{ env.PBCLI_VERSION }} 29 | release_name: ${{ env.PBCLI_VERSION }} 30 | draft: false 31 | prerelease: false 32 | 33 | release_assets: 34 | name: Release assets 35 | needs: create_release 36 | runs-on: ${{ matrix.config.os }} 37 | strategy: 38 | matrix: 39 | config: 40 | - os: ubuntu-latest 41 | name: linux 42 | steps: 43 | - name: Checkout code 44 | uses: actions/checkout@v1 45 | 46 | - name: Install packages (Ubuntu) 47 | if: matrix.config.os == 'ubuntu-latest' 48 | run: | 49 | sudo apt-get update && sudo apt-get install -y --no-install-recommends asciidoctor zsh xz-utils liblz4-tool musl-tools pkg-config libssl-dev 50 | 51 | - name: Install Rust 52 | uses: actions-rs/toolchain@v1 53 | with: 54 | toolchain: nightly 55 | profile: minimal 56 | override: true 57 | target: ${{ matrix.target }} 58 | 59 | - name: Build release binary 60 | run: | 61 | cargo build --verbose --release 62 | 63 | - name: Strip 64 | run: strip "target/release/pbcli" 65 | 66 | - name: Build archive 67 | shell: bash 68 | run: | 69 | staging="pbcli-${{ needs.create_release.outputs.pbcli_version }}-${{ matrix.config.name }}" 70 | mkdir -p "$staging" 71 | cp "target/release/pbcli" "$staging/" 72 | tar czf "$staging.tar.gz" "$staging" 73 | echo "ASSET=$staging.tar.gz" >> $GITHUB_ENV 74 | 75 | - name: Upload release assets 76 | uses: actions/upload-release-asset@v1 77 | env: 78 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 79 | with: 80 | upload_url: ${{ needs.create_release.outputs.upload_url }} 81 | asset_name: ${{ env.ASSET }} 82 | asset_path: ${{ env.ASSET }} 83 | asset_content_type: application/octet-stream -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | 3 | .idea/ 4 | .vscode/ -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aead" 22 | version = "0.4.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" 25 | dependencies = [ 26 | "generic-array", 27 | ] 28 | 29 | [[package]] 30 | name = "aes" 31 | version = "0.7.5" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" 34 | dependencies = [ 35 | "cfg-if", 36 | "cipher", 37 | "cpufeatures", 38 | "opaque-debug", 39 | ] 40 | 41 | [[package]] 42 | name = "aes-gcm" 43 | version = "0.9.4" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" 46 | dependencies = [ 47 | "aead", 48 | "aes", 49 | "cipher", 50 | "ctr", 51 | "ghash", 52 | "subtle", 53 | ] 54 | 55 | [[package]] 56 | name = "ahash" 57 | version = "0.8.11" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 60 | dependencies = [ 61 | "cfg-if", 62 | "getrandom", 63 | "once_cell", 64 | "version_check", 65 | "zerocopy", 66 | ] 67 | 68 | [[package]] 69 | name = "anstream" 70 | version = "0.6.14" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" 73 | dependencies = [ 74 | "anstyle", 75 | "anstyle-parse", 76 | "anstyle-query", 77 | "anstyle-wincon", 78 | "colorchoice", 79 | "is_terminal_polyfill", 80 | "utf8parse", 81 | ] 82 | 83 | [[package]] 84 | name = "anstyle" 85 | version = "1.0.10" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 88 | 89 | [[package]] 90 | name = "anstyle-parse" 91 | version = "0.2.4" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" 94 | dependencies = [ 95 | "utf8parse", 96 | ] 97 | 98 | [[package]] 99 | name = "anstyle-query" 100 | version = "1.0.3" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" 103 | dependencies = [ 104 | "windows-sys 0.52.0", 105 | ] 106 | 107 | [[package]] 108 | name = "anstyle-wincon" 109 | version = "3.0.3" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" 112 | dependencies = [ 113 | "anstyle", 114 | "windows-sys 0.52.0", 115 | ] 116 | 117 | [[package]] 118 | name = "anyhow" 119 | version = "1.0.81" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" 122 | 123 | [[package]] 124 | name = "askama" 125 | version = "0.12.1" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" 128 | dependencies = [ 129 | "askama_derive", 130 | "askama_escape", 131 | ] 132 | 133 | [[package]] 134 | name = "askama_derive" 135 | version = "0.12.5" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" 138 | dependencies = [ 139 | "askama_parser", 140 | "basic-toml", 141 | "mime", 142 | "mime_guess", 143 | "proc-macro2", 144 | "quote", 145 | "serde", 146 | "syn 2.0.57", 147 | ] 148 | 149 | [[package]] 150 | name = "askama_escape" 151 | version = "0.10.3" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" 154 | 155 | [[package]] 156 | name = "askama_parser" 157 | version = "0.2.1" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" 160 | dependencies = [ 161 | "nom", 162 | ] 163 | 164 | [[package]] 165 | name = "autocfg" 166 | version = "1.2.0" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" 169 | 170 | [[package]] 171 | name = "backtrace" 172 | version = "0.3.71" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" 175 | dependencies = [ 176 | "addr2line", 177 | "cc", 178 | "cfg-if", 179 | "libc", 180 | "miniz_oxide 0.7.2", 181 | "object", 182 | "rustc-demangle", 183 | ] 184 | 185 | [[package]] 186 | name = "base64" 187 | version = "0.13.1" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 190 | 191 | [[package]] 192 | name = "base64" 193 | version = "0.21.7" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 196 | 197 | [[package]] 198 | name = "base64ct" 199 | version = "1.0.1" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" 202 | 203 | [[package]] 204 | name = "basic-toml" 205 | version = "0.1.9" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" 208 | dependencies = [ 209 | "serde", 210 | ] 211 | 212 | [[package]] 213 | name = "bincode" 214 | version = "1.3.3" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 217 | dependencies = [ 218 | "serde", 219 | ] 220 | 221 | [[package]] 222 | name = "bitflags" 223 | version = "1.3.2" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 226 | 227 | [[package]] 228 | name = "bitflags" 229 | version = "2.5.0" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 232 | 233 | [[package]] 234 | name = "block-buffer" 235 | version = "0.9.0" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 238 | dependencies = [ 239 | "generic-array", 240 | ] 241 | 242 | [[package]] 243 | name = "bs58" 244 | version = "0.4.0" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" 247 | 248 | [[package]] 249 | name = "bumpalo" 250 | version = "3.15.4" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" 253 | 254 | [[package]] 255 | name = "byteorder" 256 | version = "1.5.0" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 259 | 260 | [[package]] 261 | name = "bytes" 262 | version = "1.6.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" 265 | 266 | [[package]] 267 | name = "camino" 268 | version = "1.1.6" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" 271 | dependencies = [ 272 | "serde", 273 | ] 274 | 275 | [[package]] 276 | name = "cargo-platform" 277 | version = "0.1.8" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" 280 | dependencies = [ 281 | "serde", 282 | ] 283 | 284 | [[package]] 285 | name = "cargo_metadata" 286 | version = "0.15.4" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" 289 | dependencies = [ 290 | "camino", 291 | "cargo-platform", 292 | "semver", 293 | "serde", 294 | "serde_json", 295 | "thiserror", 296 | ] 297 | 298 | [[package]] 299 | name = "cc" 300 | version = "1.0.90" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" 303 | 304 | [[package]] 305 | name = "cfg-if" 306 | version = "1.0.0" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 309 | 310 | [[package]] 311 | name = "cipher" 312 | version = "0.3.0" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" 315 | dependencies = [ 316 | "generic-array", 317 | ] 318 | 319 | [[package]] 320 | name = "clap" 321 | version = "4.5.29" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184" 324 | dependencies = [ 325 | "clap_builder", 326 | "clap_derive", 327 | ] 328 | 329 | [[package]] 330 | name = "clap_builder" 331 | version = "4.5.29" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9" 334 | dependencies = [ 335 | "anstream", 336 | "anstyle", 337 | "clap_lex", 338 | "strsim 0.11.1", 339 | ] 340 | 341 | [[package]] 342 | name = "clap_derive" 343 | version = "4.5.28" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" 346 | dependencies = [ 347 | "heck", 348 | "proc-macro2", 349 | "quote", 350 | "syn 2.0.57", 351 | ] 352 | 353 | [[package]] 354 | name = "clap_lex" 355 | version = "0.7.4" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 358 | 359 | [[package]] 360 | name = "colorchoice" 361 | version = "1.0.1" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" 364 | 365 | [[package]] 366 | name = "console" 367 | version = "0.15.8" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" 370 | dependencies = [ 371 | "encode_unicode", 372 | "lazy_static", 373 | "libc", 374 | "unicode-width", 375 | "windows-sys 0.52.0", 376 | ] 377 | 378 | [[package]] 379 | name = "core-foundation" 380 | version = "0.9.4" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 383 | dependencies = [ 384 | "core-foundation-sys", 385 | "libc", 386 | ] 387 | 388 | [[package]] 389 | name = "core-foundation-sys" 390 | version = "0.8.6" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 393 | 394 | [[package]] 395 | name = "cpufeatures" 396 | version = "0.2.12" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 399 | dependencies = [ 400 | "libc", 401 | ] 402 | 403 | [[package]] 404 | name = "crypto-mac" 405 | version = "0.11.1" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" 408 | dependencies = [ 409 | "generic-array", 410 | "subtle", 411 | ] 412 | 413 | [[package]] 414 | name = "cssparser" 415 | version = "0.34.0" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "b7c66d1cd8ed61bf80b38432613a7a2f09401ab8d0501110655f8b341484a3e3" 418 | dependencies = [ 419 | "cssparser-macros", 420 | "dtoa-short", 421 | "itoa", 422 | "phf", 423 | "smallvec", 424 | ] 425 | 426 | [[package]] 427 | name = "cssparser-macros" 428 | version = "0.6.1" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" 431 | dependencies = [ 432 | "quote", 433 | "syn 2.0.57", 434 | ] 435 | 436 | [[package]] 437 | name = "ctr" 438 | version = "0.8.0" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" 441 | dependencies = [ 442 | "cipher", 443 | ] 444 | 445 | [[package]] 446 | name = "darling" 447 | version = "0.13.4" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" 450 | dependencies = [ 451 | "darling_core", 452 | "darling_macro", 453 | ] 454 | 455 | [[package]] 456 | name = "darling_core" 457 | version = "0.13.4" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" 460 | dependencies = [ 461 | "fnv", 462 | "ident_case", 463 | "proc-macro2", 464 | "quote", 465 | "strsim 0.10.0", 466 | "syn 1.0.109", 467 | ] 468 | 469 | [[package]] 470 | name = "darling_macro" 471 | version = "0.13.4" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" 474 | dependencies = [ 475 | "darling_core", 476 | "quote", 477 | "syn 1.0.109", 478 | ] 479 | 480 | [[package]] 481 | name = "data-url" 482 | version = "0.1.1" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193" 485 | dependencies = [ 486 | "matches", 487 | ] 488 | 489 | [[package]] 490 | name = "derive_more" 491 | version = "0.99.18" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" 494 | dependencies = [ 495 | "proc-macro2", 496 | "quote", 497 | "syn 2.0.57", 498 | ] 499 | 500 | [[package]] 501 | name = "dialoguer" 502 | version = "0.9.0" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "61579ada4ec0c6031cfac3f86fdba0d195a7ebeb5e36693bd53cb5999a25beeb" 505 | dependencies = [ 506 | "console", 507 | "lazy_static", 508 | "tempfile", 509 | "zeroize", 510 | ] 511 | 512 | [[package]] 513 | name = "digest" 514 | version = "0.9.0" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 517 | dependencies = [ 518 | "generic-array", 519 | ] 520 | 521 | [[package]] 522 | name = "directories" 523 | version = "5.0.1" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" 526 | dependencies = [ 527 | "dirs-sys", 528 | ] 529 | 530 | [[package]] 531 | name = "dirs-sys" 532 | version = "0.4.1" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" 535 | dependencies = [ 536 | "libc", 537 | "option-ext", 538 | "redox_users", 539 | "windows-sys 0.48.0", 540 | ] 541 | 542 | [[package]] 543 | name = "dtoa" 544 | version = "1.0.9" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" 547 | 548 | [[package]] 549 | name = "dtoa-short" 550 | version = "0.3.5" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" 553 | dependencies = [ 554 | "dtoa", 555 | ] 556 | 557 | [[package]] 558 | name = "ego-tree" 559 | version = "0.9.0" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "7c6ba7d4eec39eaa9ab24d44a0e73a7949a1095a8b3f3abb11eddf27dbb56a53" 562 | 563 | [[package]] 564 | name = "encode_unicode" 565 | version = "0.3.6" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 568 | 569 | [[package]] 570 | name = "encoding_rs" 571 | version = "0.8.33" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" 574 | dependencies = [ 575 | "cfg-if", 576 | ] 577 | 578 | [[package]] 579 | name = "equivalent" 580 | version = "1.0.1" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 583 | 584 | [[package]] 585 | name = "errno" 586 | version = "0.3.8" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 589 | dependencies = [ 590 | "libc", 591 | "windows-sys 0.52.0", 592 | ] 593 | 594 | [[package]] 595 | name = "fastrand" 596 | version = "2.0.2" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" 599 | 600 | [[package]] 601 | name = "fnv" 602 | version = "1.0.7" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 605 | 606 | [[package]] 607 | name = "foreign-types" 608 | version = "0.3.2" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 611 | dependencies = [ 612 | "foreign-types-shared", 613 | ] 614 | 615 | [[package]] 616 | name = "foreign-types-shared" 617 | version = "0.1.1" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 620 | 621 | [[package]] 622 | name = "form_urlencoded" 623 | version = "1.2.1" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 626 | dependencies = [ 627 | "percent-encoding", 628 | ] 629 | 630 | [[package]] 631 | name = "fs-err" 632 | version = "2.11.0" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" 635 | dependencies = [ 636 | "autocfg", 637 | ] 638 | 639 | [[package]] 640 | name = "futf" 641 | version = "0.1.5" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" 644 | dependencies = [ 645 | "mac", 646 | "new_debug_unreachable", 647 | ] 648 | 649 | [[package]] 650 | name = "futures-channel" 651 | version = "0.3.30" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 654 | dependencies = [ 655 | "futures-core", 656 | "futures-sink", 657 | ] 658 | 659 | [[package]] 660 | name = "futures-core" 661 | version = "0.3.30" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 664 | 665 | [[package]] 666 | name = "futures-io" 667 | version = "0.3.30" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 670 | 671 | [[package]] 672 | name = "futures-sink" 673 | version = "0.3.30" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 676 | 677 | [[package]] 678 | name = "futures-task" 679 | version = "0.3.30" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 682 | 683 | [[package]] 684 | name = "futures-util" 685 | version = "0.3.30" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 688 | dependencies = [ 689 | "futures-core", 690 | "futures-io", 691 | "futures-sink", 692 | "futures-task", 693 | "memchr", 694 | "pin-project-lite", 695 | "pin-utils", 696 | "slab", 697 | ] 698 | 699 | [[package]] 700 | name = "fxhash" 701 | version = "0.2.1" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" 704 | dependencies = [ 705 | "byteorder", 706 | ] 707 | 708 | [[package]] 709 | name = "generic-array" 710 | version = "0.14.7" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 713 | dependencies = [ 714 | "typenum", 715 | "version_check", 716 | ] 717 | 718 | [[package]] 719 | name = "getopts" 720 | version = "0.2.21" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" 723 | dependencies = [ 724 | "unicode-width", 725 | ] 726 | 727 | [[package]] 728 | name = "getrandom" 729 | version = "0.2.12" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" 732 | dependencies = [ 733 | "cfg-if", 734 | "libc", 735 | "wasi", 736 | ] 737 | 738 | [[package]] 739 | name = "ghash" 740 | version = "0.4.4" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" 743 | dependencies = [ 744 | "opaque-debug", 745 | "polyval", 746 | ] 747 | 748 | [[package]] 749 | name = "gimli" 750 | version = "0.28.1" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 753 | 754 | [[package]] 755 | name = "glob" 756 | version = "0.3.1" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 759 | 760 | [[package]] 761 | name = "goblin" 762 | version = "0.8.2" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" 765 | dependencies = [ 766 | "log", 767 | "plain", 768 | "scroll", 769 | ] 770 | 771 | [[package]] 772 | name = "h2" 773 | version = "0.4.3" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4" 776 | dependencies = [ 777 | "bytes", 778 | "fnv", 779 | "futures-core", 780 | "futures-sink", 781 | "futures-util", 782 | "http", 783 | "indexmap", 784 | "slab", 785 | "tokio", 786 | "tokio-util", 787 | "tracing", 788 | ] 789 | 790 | [[package]] 791 | name = "hashbrown" 792 | version = "0.14.3" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 795 | 796 | [[package]] 797 | name = "heck" 798 | version = "0.5.0" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 801 | 802 | [[package]] 803 | name = "hermit-abi" 804 | version = "0.3.9" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 807 | 808 | [[package]] 809 | name = "hex-literal" 810 | version = "0.3.4" 811 | source = "registry+https://github.com/rust-lang/crates.io-index" 812 | checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" 813 | 814 | [[package]] 815 | name = "hmac" 816 | version = "0.11.0" 817 | source = "registry+https://github.com/rust-lang/crates.io-index" 818 | checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" 819 | dependencies = [ 820 | "crypto-mac", 821 | "digest", 822 | ] 823 | 824 | [[package]] 825 | name = "html5ever" 826 | version = "0.29.0" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "2e15626aaf9c351bc696217cbe29cb9b5e86c43f8a46b5e2f5c6c5cf7cb904ce" 829 | dependencies = [ 830 | "log", 831 | "mac", 832 | "markup5ever", 833 | "proc-macro2", 834 | "quote", 835 | "syn 2.0.57", 836 | ] 837 | 838 | [[package]] 839 | name = "http" 840 | version = "1.1.0" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 843 | dependencies = [ 844 | "bytes", 845 | "fnv", 846 | "itoa", 847 | ] 848 | 849 | [[package]] 850 | name = "http-body" 851 | version = "1.0.0" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" 854 | dependencies = [ 855 | "bytes", 856 | "http", 857 | ] 858 | 859 | [[package]] 860 | name = "http-body-util" 861 | version = "0.1.1" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" 864 | dependencies = [ 865 | "bytes", 866 | "futures-core", 867 | "http", 868 | "http-body", 869 | "pin-project-lite", 870 | ] 871 | 872 | [[package]] 873 | name = "httparse" 874 | version = "1.8.0" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 877 | 878 | [[package]] 879 | name = "hyper" 880 | version = "1.2.0" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" 883 | dependencies = [ 884 | "bytes", 885 | "futures-channel", 886 | "futures-util", 887 | "h2", 888 | "http", 889 | "http-body", 890 | "httparse", 891 | "itoa", 892 | "pin-project-lite", 893 | "smallvec", 894 | "tokio", 895 | "want", 896 | ] 897 | 898 | [[package]] 899 | name = "hyper-tls" 900 | version = "0.6.0" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 903 | dependencies = [ 904 | "bytes", 905 | "http-body-util", 906 | "hyper", 907 | "hyper-util", 908 | "native-tls", 909 | "tokio", 910 | "tokio-native-tls", 911 | "tower-service", 912 | ] 913 | 914 | [[package]] 915 | name = "hyper-util" 916 | version = "0.1.3" 917 | source = "registry+https://github.com/rust-lang/crates.io-index" 918 | checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" 919 | dependencies = [ 920 | "bytes", 921 | "futures-channel", 922 | "futures-util", 923 | "http", 924 | "http-body", 925 | "hyper", 926 | "pin-project-lite", 927 | "socket2", 928 | "tokio", 929 | "tower", 930 | "tower-service", 931 | "tracing", 932 | ] 933 | 934 | [[package]] 935 | name = "ident_case" 936 | version = "1.0.1" 937 | source = "registry+https://github.com/rust-lang/crates.io-index" 938 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 939 | 940 | [[package]] 941 | name = "idna" 942 | version = "0.5.0" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 945 | dependencies = [ 946 | "unicode-bidi", 947 | "unicode-normalization", 948 | ] 949 | 950 | [[package]] 951 | name = "indexmap" 952 | version = "2.2.6" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 955 | dependencies = [ 956 | "equivalent", 957 | "hashbrown", 958 | ] 959 | 960 | [[package]] 961 | name = "ipnet" 962 | version = "2.9.0" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" 965 | 966 | [[package]] 967 | name = "is_terminal_polyfill" 968 | version = "1.70.0" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" 971 | 972 | [[package]] 973 | name = "itoa" 974 | version = "1.0.11" 975 | source = "registry+https://github.com/rust-lang/crates.io-index" 976 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 977 | 978 | [[package]] 979 | name = "js-sys" 980 | version = "0.3.69" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 983 | dependencies = [ 984 | "wasm-bindgen", 985 | ] 986 | 987 | [[package]] 988 | name = "lazy_static" 989 | version = "1.4.0" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 992 | 993 | [[package]] 994 | name = "libc" 995 | version = "0.2.153" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 998 | 999 | [[package]] 1000 | name = "libredox" 1001 | version = "0.1.3" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 1004 | dependencies = [ 1005 | "bitflags 2.5.0", 1006 | "libc", 1007 | ] 1008 | 1009 | [[package]] 1010 | name = "linux-raw-sys" 1011 | version = "0.4.13" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" 1014 | 1015 | [[package]] 1016 | name = "lock_api" 1017 | version = "0.4.12" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 1020 | dependencies = [ 1021 | "autocfg", 1022 | "scopeguard", 1023 | ] 1024 | 1025 | [[package]] 1026 | name = "log" 1027 | version = "0.4.22" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 1030 | 1031 | [[package]] 1032 | name = "mac" 1033 | version = "0.1.1" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" 1036 | 1037 | [[package]] 1038 | name = "markup5ever" 1039 | version = "0.14.0" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "82c88c6129bd24319e62a0359cb6b958fa7e8be6e19bb1663bc396b90883aca5" 1042 | dependencies = [ 1043 | "log", 1044 | "phf", 1045 | "phf_codegen", 1046 | "string_cache", 1047 | "string_cache_codegen", 1048 | "tendril", 1049 | ] 1050 | 1051 | [[package]] 1052 | name = "matches" 1053 | version = "0.1.10" 1054 | source = "registry+https://github.com/rust-lang/crates.io-index" 1055 | checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" 1056 | 1057 | [[package]] 1058 | name = "memchr" 1059 | version = "2.7.2" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" 1062 | 1063 | [[package]] 1064 | name = "mime" 1065 | version = "0.3.17" 1066 | source = "registry+https://github.com/rust-lang/crates.io-index" 1067 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1068 | 1069 | [[package]] 1070 | name = "mime_guess" 1071 | version = "2.0.4" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" 1074 | dependencies = [ 1075 | "mime", 1076 | "unicase", 1077 | ] 1078 | 1079 | [[package]] 1080 | name = "minimal-lexical" 1081 | version = "0.2.1" 1082 | source = "registry+https://github.com/rust-lang/crates.io-index" 1083 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 1084 | 1085 | [[package]] 1086 | name = "miniz_oxide" 1087 | version = "0.5.4" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" 1090 | dependencies = [ 1091 | "adler", 1092 | ] 1093 | 1094 | [[package]] 1095 | name = "miniz_oxide" 1096 | version = "0.7.2" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" 1099 | dependencies = [ 1100 | "adler", 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "mio" 1105 | version = "0.8.11" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 1108 | dependencies = [ 1109 | "libc", 1110 | "wasi", 1111 | "windows-sys 0.48.0", 1112 | ] 1113 | 1114 | [[package]] 1115 | name = "native-tls" 1116 | version = "0.2.11" 1117 | source = "registry+https://github.com/rust-lang/crates.io-index" 1118 | checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" 1119 | dependencies = [ 1120 | "lazy_static", 1121 | "libc", 1122 | "log", 1123 | "openssl", 1124 | "openssl-probe", 1125 | "openssl-sys", 1126 | "schannel", 1127 | "security-framework", 1128 | "security-framework-sys", 1129 | "tempfile", 1130 | ] 1131 | 1132 | [[package]] 1133 | name = "new_debug_unreachable" 1134 | version = "1.0.6" 1135 | source = "registry+https://github.com/rust-lang/crates.io-index" 1136 | checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" 1137 | 1138 | [[package]] 1139 | name = "nom" 1140 | version = "7.1.3" 1141 | source = "registry+https://github.com/rust-lang/crates.io-index" 1142 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 1143 | dependencies = [ 1144 | "memchr", 1145 | "minimal-lexical", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "num_cpus" 1150 | version = "1.16.0" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 1153 | dependencies = [ 1154 | "hermit-abi", 1155 | "libc", 1156 | ] 1157 | 1158 | [[package]] 1159 | name = "object" 1160 | version = "0.32.2" 1161 | source = "registry+https://github.com/rust-lang/crates.io-index" 1162 | checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" 1163 | dependencies = [ 1164 | "memchr", 1165 | ] 1166 | 1167 | [[package]] 1168 | name = "once_cell" 1169 | version = "1.19.0" 1170 | source = "registry+https://github.com/rust-lang/crates.io-index" 1171 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 1172 | 1173 | [[package]] 1174 | name = "opaque-debug" 1175 | version = "0.3.1" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" 1178 | 1179 | [[package]] 1180 | name = "openssl" 1181 | version = "0.10.64" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" 1184 | dependencies = [ 1185 | "bitflags 2.5.0", 1186 | "cfg-if", 1187 | "foreign-types", 1188 | "libc", 1189 | "once_cell", 1190 | "openssl-macros", 1191 | "openssl-sys", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "openssl-macros" 1196 | version = "0.1.1" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1199 | dependencies = [ 1200 | "proc-macro2", 1201 | "quote", 1202 | "syn 2.0.57", 1203 | ] 1204 | 1205 | [[package]] 1206 | name = "openssl-probe" 1207 | version = "0.1.5" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1210 | 1211 | [[package]] 1212 | name = "openssl-src" 1213 | version = "300.2.3+3.2.1" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "5cff92b6f71555b61bb9315f7c64da3ca43d87531622120fea0195fc761b4843" 1216 | dependencies = [ 1217 | "cc", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "openssl-sys" 1222 | version = "0.9.102" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" 1225 | dependencies = [ 1226 | "cc", 1227 | "libc", 1228 | "openssl-src", 1229 | "pkg-config", 1230 | "vcpkg", 1231 | ] 1232 | 1233 | [[package]] 1234 | name = "option-ext" 1235 | version = "0.2.0" 1236 | source = "registry+https://github.com/rust-lang/crates.io-index" 1237 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 1238 | 1239 | [[package]] 1240 | name = "parking_lot" 1241 | version = "0.12.3" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1244 | dependencies = [ 1245 | "lock_api", 1246 | "parking_lot_core", 1247 | ] 1248 | 1249 | [[package]] 1250 | name = "parking_lot_core" 1251 | version = "0.9.10" 1252 | source = "registry+https://github.com/rust-lang/crates.io-index" 1253 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1254 | dependencies = [ 1255 | "cfg-if", 1256 | "libc", 1257 | "redox_syscall", 1258 | "smallvec", 1259 | "windows-targets 0.52.4", 1260 | ] 1261 | 1262 | [[package]] 1263 | name = "parse-size" 1264 | version = "1.0.0" 1265 | source = "registry+https://github.com/rust-lang/crates.io-index" 1266 | checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae" 1267 | 1268 | [[package]] 1269 | name = "password-hash" 1270 | version = "0.3.2" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" 1273 | dependencies = [ 1274 | "base64ct", 1275 | "rand_core", 1276 | "subtle", 1277 | ] 1278 | 1279 | [[package]] 1280 | name = "paste" 1281 | version = "1.0.14" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" 1284 | 1285 | [[package]] 1286 | name = "pbcli" 1287 | version = "2.8.0" 1288 | dependencies = [ 1289 | "aes-gcm", 1290 | "base64 0.13.1", 1291 | "bs58", 1292 | "clap", 1293 | "crypto-mac", 1294 | "data-url", 1295 | "dialoguer", 1296 | "directories", 1297 | "hex-literal", 1298 | "hmac", 1299 | "log", 1300 | "mime_guess", 1301 | "miniz_oxide 0.5.4", 1302 | "openssl", 1303 | "parse-size", 1304 | "pbkdf2", 1305 | "rand_chacha", 1306 | "rand_core", 1307 | "reqwest", 1308 | "ring", 1309 | "scraper", 1310 | "serde", 1311 | "serde_json", 1312 | "serde_with", 1313 | "sha2", 1314 | "terminal_size", 1315 | "typenum", 1316 | "uniffi", 1317 | "url", 1318 | ] 1319 | 1320 | [[package]] 1321 | name = "pbkdf2" 1322 | version = "0.9.0" 1323 | source = "registry+https://github.com/rust-lang/crates.io-index" 1324 | checksum = "f05894bce6a1ba4be299d0c5f29563e08af2bc18bb7d48313113bed71e904739" 1325 | dependencies = [ 1326 | "crypto-mac", 1327 | "hmac", 1328 | "password-hash", 1329 | "sha2", 1330 | ] 1331 | 1332 | [[package]] 1333 | name = "percent-encoding" 1334 | version = "2.3.1" 1335 | source = "registry+https://github.com/rust-lang/crates.io-index" 1336 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1337 | 1338 | [[package]] 1339 | name = "phf" 1340 | version = "0.11.2" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" 1343 | dependencies = [ 1344 | "phf_macros", 1345 | "phf_shared 0.11.2", 1346 | ] 1347 | 1348 | [[package]] 1349 | name = "phf_codegen" 1350 | version = "0.11.2" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" 1353 | dependencies = [ 1354 | "phf_generator 0.11.2", 1355 | "phf_shared 0.11.2", 1356 | ] 1357 | 1358 | [[package]] 1359 | name = "phf_generator" 1360 | version = "0.10.0" 1361 | source = "registry+https://github.com/rust-lang/crates.io-index" 1362 | checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" 1363 | dependencies = [ 1364 | "phf_shared 0.10.0", 1365 | "rand", 1366 | ] 1367 | 1368 | [[package]] 1369 | name = "phf_generator" 1370 | version = "0.11.2" 1371 | source = "registry+https://github.com/rust-lang/crates.io-index" 1372 | checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" 1373 | dependencies = [ 1374 | "phf_shared 0.11.2", 1375 | "rand", 1376 | ] 1377 | 1378 | [[package]] 1379 | name = "phf_macros" 1380 | version = "0.11.2" 1381 | source = "registry+https://github.com/rust-lang/crates.io-index" 1382 | checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" 1383 | dependencies = [ 1384 | "phf_generator 0.11.2", 1385 | "phf_shared 0.11.2", 1386 | "proc-macro2", 1387 | "quote", 1388 | "syn 2.0.57", 1389 | ] 1390 | 1391 | [[package]] 1392 | name = "phf_shared" 1393 | version = "0.10.0" 1394 | source = "registry+https://github.com/rust-lang/crates.io-index" 1395 | checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" 1396 | dependencies = [ 1397 | "siphasher", 1398 | ] 1399 | 1400 | [[package]] 1401 | name = "phf_shared" 1402 | version = "0.11.2" 1403 | source = "registry+https://github.com/rust-lang/crates.io-index" 1404 | checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" 1405 | dependencies = [ 1406 | "siphasher", 1407 | ] 1408 | 1409 | [[package]] 1410 | name = "pin-project" 1411 | version = "1.1.5" 1412 | source = "registry+https://github.com/rust-lang/crates.io-index" 1413 | checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" 1414 | dependencies = [ 1415 | "pin-project-internal", 1416 | ] 1417 | 1418 | [[package]] 1419 | name = "pin-project-internal" 1420 | version = "1.1.5" 1421 | source = "registry+https://github.com/rust-lang/crates.io-index" 1422 | checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" 1423 | dependencies = [ 1424 | "proc-macro2", 1425 | "quote", 1426 | "syn 2.0.57", 1427 | ] 1428 | 1429 | [[package]] 1430 | name = "pin-project-lite" 1431 | version = "0.2.14" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 1434 | 1435 | [[package]] 1436 | name = "pin-utils" 1437 | version = "0.1.0" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1440 | 1441 | [[package]] 1442 | name = "pkg-config" 1443 | version = "0.3.30" 1444 | source = "registry+https://github.com/rust-lang/crates.io-index" 1445 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 1446 | 1447 | [[package]] 1448 | name = "plain" 1449 | version = "0.2.3" 1450 | source = "registry+https://github.com/rust-lang/crates.io-index" 1451 | checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" 1452 | 1453 | [[package]] 1454 | name = "polyval" 1455 | version = "0.5.3" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" 1458 | dependencies = [ 1459 | "cfg-if", 1460 | "cpufeatures", 1461 | "opaque-debug", 1462 | "universal-hash", 1463 | ] 1464 | 1465 | [[package]] 1466 | name = "ppv-lite86" 1467 | version = "0.2.17" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1470 | 1471 | [[package]] 1472 | name = "precomputed-hash" 1473 | version = "0.1.1" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 1476 | 1477 | [[package]] 1478 | name = "proc-macro2" 1479 | version = "1.0.79" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" 1482 | dependencies = [ 1483 | "unicode-ident", 1484 | ] 1485 | 1486 | [[package]] 1487 | name = "quote" 1488 | version = "1.0.35" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 1491 | dependencies = [ 1492 | "proc-macro2", 1493 | ] 1494 | 1495 | [[package]] 1496 | name = "rand" 1497 | version = "0.8.5" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1500 | dependencies = [ 1501 | "libc", 1502 | "rand_chacha", 1503 | "rand_core", 1504 | ] 1505 | 1506 | [[package]] 1507 | name = "rand_chacha" 1508 | version = "0.3.1" 1509 | source = "registry+https://github.com/rust-lang/crates.io-index" 1510 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1511 | dependencies = [ 1512 | "ppv-lite86", 1513 | "rand_core", 1514 | ] 1515 | 1516 | [[package]] 1517 | name = "rand_core" 1518 | version = "0.6.4" 1519 | source = "registry+https://github.com/rust-lang/crates.io-index" 1520 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1521 | dependencies = [ 1522 | "getrandom", 1523 | ] 1524 | 1525 | [[package]] 1526 | name = "redox_syscall" 1527 | version = "0.5.7" 1528 | source = "registry+https://github.com/rust-lang/crates.io-index" 1529 | checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" 1530 | dependencies = [ 1531 | "bitflags 2.5.0", 1532 | ] 1533 | 1534 | [[package]] 1535 | name = "redox_users" 1536 | version = "0.4.6" 1537 | source = "registry+https://github.com/rust-lang/crates.io-index" 1538 | checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" 1539 | dependencies = [ 1540 | "getrandom", 1541 | "libredox", 1542 | "thiserror", 1543 | ] 1544 | 1545 | [[package]] 1546 | name = "reqwest" 1547 | version = "0.12.2" 1548 | source = "registry+https://github.com/rust-lang/crates.io-index" 1549 | checksum = "2d66674f2b6fb864665eea7a3c1ac4e3dfacd2fda83cf6f935a612e01b0e3338" 1550 | dependencies = [ 1551 | "base64 0.21.7", 1552 | "bytes", 1553 | "encoding_rs", 1554 | "futures-channel", 1555 | "futures-core", 1556 | "futures-util", 1557 | "h2", 1558 | "http", 1559 | "http-body", 1560 | "http-body-util", 1561 | "hyper", 1562 | "hyper-tls", 1563 | "hyper-util", 1564 | "ipnet", 1565 | "js-sys", 1566 | "log", 1567 | "mime", 1568 | "native-tls", 1569 | "once_cell", 1570 | "percent-encoding", 1571 | "pin-project-lite", 1572 | "rustls-pemfile", 1573 | "serde", 1574 | "serde_json", 1575 | "serde_urlencoded", 1576 | "sync_wrapper", 1577 | "system-configuration", 1578 | "tokio", 1579 | "tokio-native-tls", 1580 | "tower-service", 1581 | "url", 1582 | "wasm-bindgen", 1583 | "wasm-bindgen-futures", 1584 | "web-sys", 1585 | "winreg", 1586 | ] 1587 | 1588 | [[package]] 1589 | name = "ring" 1590 | version = "0.16.20" 1591 | source = "registry+https://github.com/rust-lang/crates.io-index" 1592 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1593 | dependencies = [ 1594 | "cc", 1595 | "libc", 1596 | "once_cell", 1597 | "spin", 1598 | "untrusted", 1599 | "web-sys", 1600 | "winapi", 1601 | ] 1602 | 1603 | [[package]] 1604 | name = "rustc-demangle" 1605 | version = "0.1.23" 1606 | source = "registry+https://github.com/rust-lang/crates.io-index" 1607 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 1608 | 1609 | [[package]] 1610 | name = "rustix" 1611 | version = "0.38.32" 1612 | source = "registry+https://github.com/rust-lang/crates.io-index" 1613 | checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" 1614 | dependencies = [ 1615 | "bitflags 2.5.0", 1616 | "errno", 1617 | "libc", 1618 | "linux-raw-sys", 1619 | "windows-sys 0.52.0", 1620 | ] 1621 | 1622 | [[package]] 1623 | name = "rustls-pemfile" 1624 | version = "1.0.4" 1625 | source = "registry+https://github.com/rust-lang/crates.io-index" 1626 | checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" 1627 | dependencies = [ 1628 | "base64 0.21.7", 1629 | ] 1630 | 1631 | [[package]] 1632 | name = "ryu" 1633 | version = "1.0.17" 1634 | source = "registry+https://github.com/rust-lang/crates.io-index" 1635 | checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" 1636 | 1637 | [[package]] 1638 | name = "schannel" 1639 | version = "0.1.23" 1640 | source = "registry+https://github.com/rust-lang/crates.io-index" 1641 | checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" 1642 | dependencies = [ 1643 | "windows-sys 0.52.0", 1644 | ] 1645 | 1646 | [[package]] 1647 | name = "scopeguard" 1648 | version = "1.2.0" 1649 | source = "registry+https://github.com/rust-lang/crates.io-index" 1650 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1651 | 1652 | [[package]] 1653 | name = "scraper" 1654 | version = "0.21.0" 1655 | source = "registry+https://github.com/rust-lang/crates.io-index" 1656 | checksum = "b0e749d29b2064585327af5038a5a8eb73aeebad4a3472e83531a436563f7208" 1657 | dependencies = [ 1658 | "ahash", 1659 | "cssparser", 1660 | "ego-tree", 1661 | "getopts", 1662 | "html5ever", 1663 | "precomputed-hash", 1664 | "selectors", 1665 | "tendril", 1666 | ] 1667 | 1668 | [[package]] 1669 | name = "scroll" 1670 | version = "0.12.0" 1671 | source = "registry+https://github.com/rust-lang/crates.io-index" 1672 | checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" 1673 | dependencies = [ 1674 | "scroll_derive", 1675 | ] 1676 | 1677 | [[package]] 1678 | name = "scroll_derive" 1679 | version = "0.12.0" 1680 | source = "registry+https://github.com/rust-lang/crates.io-index" 1681 | checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" 1682 | dependencies = [ 1683 | "proc-macro2", 1684 | "quote", 1685 | "syn 2.0.57", 1686 | ] 1687 | 1688 | [[package]] 1689 | name = "security-framework" 1690 | version = "2.10.0" 1691 | source = "registry+https://github.com/rust-lang/crates.io-index" 1692 | checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" 1693 | dependencies = [ 1694 | "bitflags 1.3.2", 1695 | "core-foundation", 1696 | "core-foundation-sys", 1697 | "libc", 1698 | "security-framework-sys", 1699 | ] 1700 | 1701 | [[package]] 1702 | name = "security-framework-sys" 1703 | version = "2.10.0" 1704 | source = "registry+https://github.com/rust-lang/crates.io-index" 1705 | checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" 1706 | dependencies = [ 1707 | "core-foundation-sys", 1708 | "libc", 1709 | ] 1710 | 1711 | [[package]] 1712 | name = "selectors" 1713 | version = "0.26.0" 1714 | source = "registry+https://github.com/rust-lang/crates.io-index" 1715 | checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8" 1716 | dependencies = [ 1717 | "bitflags 2.5.0", 1718 | "cssparser", 1719 | "derive_more", 1720 | "fxhash", 1721 | "log", 1722 | "new_debug_unreachable", 1723 | "phf", 1724 | "phf_codegen", 1725 | "precomputed-hash", 1726 | "servo_arc", 1727 | "smallvec", 1728 | ] 1729 | 1730 | [[package]] 1731 | name = "semver" 1732 | version = "1.0.22" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" 1735 | dependencies = [ 1736 | "serde", 1737 | ] 1738 | 1739 | [[package]] 1740 | name = "serde" 1741 | version = "1.0.197" 1742 | source = "registry+https://github.com/rust-lang/crates.io-index" 1743 | checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" 1744 | dependencies = [ 1745 | "serde_derive", 1746 | ] 1747 | 1748 | [[package]] 1749 | name = "serde_derive" 1750 | version = "1.0.197" 1751 | source = "registry+https://github.com/rust-lang/crates.io-index" 1752 | checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" 1753 | dependencies = [ 1754 | "proc-macro2", 1755 | "quote", 1756 | "syn 2.0.57", 1757 | ] 1758 | 1759 | [[package]] 1760 | name = "serde_json" 1761 | version = "1.0.115" 1762 | source = "registry+https://github.com/rust-lang/crates.io-index" 1763 | checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" 1764 | dependencies = [ 1765 | "itoa", 1766 | "ryu", 1767 | "serde", 1768 | ] 1769 | 1770 | [[package]] 1771 | name = "serde_urlencoded" 1772 | version = "0.7.1" 1773 | source = "registry+https://github.com/rust-lang/crates.io-index" 1774 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1775 | dependencies = [ 1776 | "form_urlencoded", 1777 | "itoa", 1778 | "ryu", 1779 | "serde", 1780 | ] 1781 | 1782 | [[package]] 1783 | name = "serde_with" 1784 | version = "1.14.0" 1785 | source = "registry+https://github.com/rust-lang/crates.io-index" 1786 | checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" 1787 | dependencies = [ 1788 | "serde", 1789 | "serde_with_macros", 1790 | ] 1791 | 1792 | [[package]] 1793 | name = "serde_with_macros" 1794 | version = "1.5.2" 1795 | source = "registry+https://github.com/rust-lang/crates.io-index" 1796 | checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" 1797 | dependencies = [ 1798 | "darling", 1799 | "proc-macro2", 1800 | "quote", 1801 | "syn 1.0.109", 1802 | ] 1803 | 1804 | [[package]] 1805 | name = "servo_arc" 1806 | version = "0.4.0" 1807 | source = "registry+https://github.com/rust-lang/crates.io-index" 1808 | checksum = "ae65c4249478a2647db249fb43e23cec56a2c8974a427e7bd8cb5a1d0964921a" 1809 | dependencies = [ 1810 | "stable_deref_trait", 1811 | ] 1812 | 1813 | [[package]] 1814 | name = "sha2" 1815 | version = "0.9.9" 1816 | source = "registry+https://github.com/rust-lang/crates.io-index" 1817 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 1818 | dependencies = [ 1819 | "block-buffer", 1820 | "cfg-if", 1821 | "cpufeatures", 1822 | "digest", 1823 | "opaque-debug", 1824 | ] 1825 | 1826 | [[package]] 1827 | name = "siphasher" 1828 | version = "0.3.11" 1829 | source = "registry+https://github.com/rust-lang/crates.io-index" 1830 | checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" 1831 | 1832 | [[package]] 1833 | name = "slab" 1834 | version = "0.4.9" 1835 | source = "registry+https://github.com/rust-lang/crates.io-index" 1836 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1837 | dependencies = [ 1838 | "autocfg", 1839 | ] 1840 | 1841 | [[package]] 1842 | name = "smallvec" 1843 | version = "1.13.2" 1844 | source = "registry+https://github.com/rust-lang/crates.io-index" 1845 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1846 | 1847 | [[package]] 1848 | name = "smawk" 1849 | version = "0.3.2" 1850 | source = "registry+https://github.com/rust-lang/crates.io-index" 1851 | checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" 1852 | 1853 | [[package]] 1854 | name = "socket2" 1855 | version = "0.5.6" 1856 | source = "registry+https://github.com/rust-lang/crates.io-index" 1857 | checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" 1858 | dependencies = [ 1859 | "libc", 1860 | "windows-sys 0.52.0", 1861 | ] 1862 | 1863 | [[package]] 1864 | name = "spin" 1865 | version = "0.5.2" 1866 | source = "registry+https://github.com/rust-lang/crates.io-index" 1867 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1868 | 1869 | [[package]] 1870 | name = "stable_deref_trait" 1871 | version = "1.2.0" 1872 | source = "registry+https://github.com/rust-lang/crates.io-index" 1873 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1874 | 1875 | [[package]] 1876 | name = "static_assertions" 1877 | version = "1.1.0" 1878 | source = "registry+https://github.com/rust-lang/crates.io-index" 1879 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 1880 | 1881 | [[package]] 1882 | name = "string_cache" 1883 | version = "0.8.7" 1884 | source = "registry+https://github.com/rust-lang/crates.io-index" 1885 | checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" 1886 | dependencies = [ 1887 | "new_debug_unreachable", 1888 | "once_cell", 1889 | "parking_lot", 1890 | "phf_shared 0.10.0", 1891 | "precomputed-hash", 1892 | "serde", 1893 | ] 1894 | 1895 | [[package]] 1896 | name = "string_cache_codegen" 1897 | version = "0.5.2" 1898 | source = "registry+https://github.com/rust-lang/crates.io-index" 1899 | checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" 1900 | dependencies = [ 1901 | "phf_generator 0.10.0", 1902 | "phf_shared 0.10.0", 1903 | "proc-macro2", 1904 | "quote", 1905 | ] 1906 | 1907 | [[package]] 1908 | name = "strsim" 1909 | version = "0.10.0" 1910 | source = "registry+https://github.com/rust-lang/crates.io-index" 1911 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1912 | 1913 | [[package]] 1914 | name = "strsim" 1915 | version = "0.11.1" 1916 | source = "registry+https://github.com/rust-lang/crates.io-index" 1917 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1918 | 1919 | [[package]] 1920 | name = "subtle" 1921 | version = "2.4.1" 1922 | source = "registry+https://github.com/rust-lang/crates.io-index" 1923 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1924 | 1925 | [[package]] 1926 | name = "syn" 1927 | version = "1.0.109" 1928 | source = "registry+https://github.com/rust-lang/crates.io-index" 1929 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1930 | dependencies = [ 1931 | "proc-macro2", 1932 | "quote", 1933 | "unicode-ident", 1934 | ] 1935 | 1936 | [[package]] 1937 | name = "syn" 1938 | version = "2.0.57" 1939 | source = "registry+https://github.com/rust-lang/crates.io-index" 1940 | checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" 1941 | dependencies = [ 1942 | "proc-macro2", 1943 | "quote", 1944 | "unicode-ident", 1945 | ] 1946 | 1947 | [[package]] 1948 | name = "sync_wrapper" 1949 | version = "0.1.2" 1950 | source = "registry+https://github.com/rust-lang/crates.io-index" 1951 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 1952 | 1953 | [[package]] 1954 | name = "system-configuration" 1955 | version = "0.5.1" 1956 | source = "registry+https://github.com/rust-lang/crates.io-index" 1957 | checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" 1958 | dependencies = [ 1959 | "bitflags 1.3.2", 1960 | "core-foundation", 1961 | "system-configuration-sys", 1962 | ] 1963 | 1964 | [[package]] 1965 | name = "system-configuration-sys" 1966 | version = "0.5.0" 1967 | source = "registry+https://github.com/rust-lang/crates.io-index" 1968 | checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" 1969 | dependencies = [ 1970 | "core-foundation-sys", 1971 | "libc", 1972 | ] 1973 | 1974 | [[package]] 1975 | name = "tempfile" 1976 | version = "3.10.1" 1977 | source = "registry+https://github.com/rust-lang/crates.io-index" 1978 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 1979 | dependencies = [ 1980 | "cfg-if", 1981 | "fastrand", 1982 | "rustix", 1983 | "windows-sys 0.52.0", 1984 | ] 1985 | 1986 | [[package]] 1987 | name = "tendril" 1988 | version = "0.4.3" 1989 | source = "registry+https://github.com/rust-lang/crates.io-index" 1990 | checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" 1991 | dependencies = [ 1992 | "futf", 1993 | "mac", 1994 | "utf-8", 1995 | ] 1996 | 1997 | [[package]] 1998 | name = "terminal_size" 1999 | version = "0.1.17" 2000 | source = "registry+https://github.com/rust-lang/crates.io-index" 2001 | checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" 2002 | dependencies = [ 2003 | "libc", 2004 | "winapi", 2005 | ] 2006 | 2007 | [[package]] 2008 | name = "textwrap" 2009 | version = "0.16.1" 2010 | source = "registry+https://github.com/rust-lang/crates.io-index" 2011 | checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" 2012 | dependencies = [ 2013 | "smawk", 2014 | ] 2015 | 2016 | [[package]] 2017 | name = "thiserror" 2018 | version = "1.0.59" 2019 | source = "registry+https://github.com/rust-lang/crates.io-index" 2020 | checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" 2021 | dependencies = [ 2022 | "thiserror-impl", 2023 | ] 2024 | 2025 | [[package]] 2026 | name = "thiserror-impl" 2027 | version = "1.0.59" 2028 | source = "registry+https://github.com/rust-lang/crates.io-index" 2029 | checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" 2030 | dependencies = [ 2031 | "proc-macro2", 2032 | "quote", 2033 | "syn 2.0.57", 2034 | ] 2035 | 2036 | [[package]] 2037 | name = "tinyvec" 2038 | version = "1.6.0" 2039 | source = "registry+https://github.com/rust-lang/crates.io-index" 2040 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 2041 | dependencies = [ 2042 | "tinyvec_macros", 2043 | ] 2044 | 2045 | [[package]] 2046 | name = "tinyvec_macros" 2047 | version = "0.1.1" 2048 | source = "registry+https://github.com/rust-lang/crates.io-index" 2049 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2050 | 2051 | [[package]] 2052 | name = "tokio" 2053 | version = "1.37.0" 2054 | source = "registry+https://github.com/rust-lang/crates.io-index" 2055 | checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" 2056 | dependencies = [ 2057 | "backtrace", 2058 | "bytes", 2059 | "libc", 2060 | "mio", 2061 | "num_cpus", 2062 | "pin-project-lite", 2063 | "socket2", 2064 | "windows-sys 0.48.0", 2065 | ] 2066 | 2067 | [[package]] 2068 | name = "tokio-native-tls" 2069 | version = "0.3.1" 2070 | source = "registry+https://github.com/rust-lang/crates.io-index" 2071 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 2072 | dependencies = [ 2073 | "native-tls", 2074 | "tokio", 2075 | ] 2076 | 2077 | [[package]] 2078 | name = "tokio-util" 2079 | version = "0.7.10" 2080 | source = "registry+https://github.com/rust-lang/crates.io-index" 2081 | checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" 2082 | dependencies = [ 2083 | "bytes", 2084 | "futures-core", 2085 | "futures-sink", 2086 | "pin-project-lite", 2087 | "tokio", 2088 | "tracing", 2089 | ] 2090 | 2091 | [[package]] 2092 | name = "toml" 2093 | version = "0.5.11" 2094 | source = "registry+https://github.com/rust-lang/crates.io-index" 2095 | checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" 2096 | dependencies = [ 2097 | "serde", 2098 | ] 2099 | 2100 | [[package]] 2101 | name = "tower" 2102 | version = "0.4.13" 2103 | source = "registry+https://github.com/rust-lang/crates.io-index" 2104 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 2105 | dependencies = [ 2106 | "futures-core", 2107 | "futures-util", 2108 | "pin-project", 2109 | "pin-project-lite", 2110 | "tokio", 2111 | "tower-layer", 2112 | "tower-service", 2113 | "tracing", 2114 | ] 2115 | 2116 | [[package]] 2117 | name = "tower-layer" 2118 | version = "0.3.2" 2119 | source = "registry+https://github.com/rust-lang/crates.io-index" 2120 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 2121 | 2122 | [[package]] 2123 | name = "tower-service" 2124 | version = "0.3.2" 2125 | source = "registry+https://github.com/rust-lang/crates.io-index" 2126 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 2127 | 2128 | [[package]] 2129 | name = "tracing" 2130 | version = "0.1.40" 2131 | source = "registry+https://github.com/rust-lang/crates.io-index" 2132 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 2133 | dependencies = [ 2134 | "log", 2135 | "pin-project-lite", 2136 | "tracing-core", 2137 | ] 2138 | 2139 | [[package]] 2140 | name = "tracing-core" 2141 | version = "0.1.32" 2142 | source = "registry+https://github.com/rust-lang/crates.io-index" 2143 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 2144 | dependencies = [ 2145 | "once_cell", 2146 | ] 2147 | 2148 | [[package]] 2149 | name = "try-lock" 2150 | version = "0.2.5" 2151 | source = "registry+https://github.com/rust-lang/crates.io-index" 2152 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2153 | 2154 | [[package]] 2155 | name = "typenum" 2156 | version = "1.17.0" 2157 | source = "registry+https://github.com/rust-lang/crates.io-index" 2158 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 2159 | 2160 | [[package]] 2161 | name = "unicase" 2162 | version = "2.7.0" 2163 | source = "registry+https://github.com/rust-lang/crates.io-index" 2164 | checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" 2165 | dependencies = [ 2166 | "version_check", 2167 | ] 2168 | 2169 | [[package]] 2170 | name = "unicode-bidi" 2171 | version = "0.3.15" 2172 | source = "registry+https://github.com/rust-lang/crates.io-index" 2173 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 2174 | 2175 | [[package]] 2176 | name = "unicode-ident" 2177 | version = "1.0.12" 2178 | source = "registry+https://github.com/rust-lang/crates.io-index" 2179 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 2180 | 2181 | [[package]] 2182 | name = "unicode-normalization" 2183 | version = "0.1.23" 2184 | source = "registry+https://github.com/rust-lang/crates.io-index" 2185 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 2186 | dependencies = [ 2187 | "tinyvec", 2188 | ] 2189 | 2190 | [[package]] 2191 | name = "unicode-width" 2192 | version = "0.1.11" 2193 | source = "registry+https://github.com/rust-lang/crates.io-index" 2194 | checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" 2195 | 2196 | [[package]] 2197 | name = "uniffi" 2198 | version = "0.28.0" 2199 | source = "registry+https://github.com/rust-lang/crates.io-index" 2200 | checksum = "f31bff6daf87277a9014bcdefbc2842b0553392919d1096843c5aad899ca4588" 2201 | dependencies = [ 2202 | "anyhow", 2203 | "camino", 2204 | "clap", 2205 | "uniffi_bindgen", 2206 | "uniffi_core", 2207 | "uniffi_macros", 2208 | ] 2209 | 2210 | [[package]] 2211 | name = "uniffi_bindgen" 2212 | version = "0.28.0" 2213 | source = "registry+https://github.com/rust-lang/crates.io-index" 2214 | checksum = "96061d7e01b185aa405f7c9b134741ab3e50cc6796a47d6fd8ab9a5364b5feed" 2215 | dependencies = [ 2216 | "anyhow", 2217 | "askama", 2218 | "camino", 2219 | "cargo_metadata", 2220 | "fs-err", 2221 | "glob", 2222 | "goblin", 2223 | "heck", 2224 | "once_cell", 2225 | "paste", 2226 | "serde", 2227 | "textwrap", 2228 | "toml", 2229 | "uniffi_meta", 2230 | "uniffi_testing", 2231 | "uniffi_udl", 2232 | ] 2233 | 2234 | [[package]] 2235 | name = "uniffi_checksum_derive" 2236 | version = "0.28.0" 2237 | source = "registry+https://github.com/rust-lang/crates.io-index" 2238 | checksum = "2fcfa22f55829d3aaa7acfb1c5150224188fe0f27c59a8a3eddcaa24d1ffbe58" 2239 | dependencies = [ 2240 | "quote", 2241 | "syn 2.0.57", 2242 | ] 2243 | 2244 | [[package]] 2245 | name = "uniffi_core" 2246 | version = "0.28.0" 2247 | source = "registry+https://github.com/rust-lang/crates.io-index" 2248 | checksum = "3210d57d6ab6065ab47a2898dacdb7c606fd6a4156196831fa3bf82e34ac58a6" 2249 | dependencies = [ 2250 | "anyhow", 2251 | "bytes", 2252 | "camino", 2253 | "log", 2254 | "once_cell", 2255 | "paste", 2256 | "static_assertions", 2257 | ] 2258 | 2259 | [[package]] 2260 | name = "uniffi_macros" 2261 | version = "0.28.0" 2262 | source = "registry+https://github.com/rust-lang/crates.io-index" 2263 | checksum = "b58691741080935437dc862122e68d7414432a11824ac1137868de46181a0bd2" 2264 | dependencies = [ 2265 | "bincode", 2266 | "camino", 2267 | "fs-err", 2268 | "once_cell", 2269 | "proc-macro2", 2270 | "quote", 2271 | "serde", 2272 | "syn 2.0.57", 2273 | "toml", 2274 | "uniffi_meta", 2275 | ] 2276 | 2277 | [[package]] 2278 | name = "uniffi_meta" 2279 | version = "0.28.0" 2280 | source = "registry+https://github.com/rust-lang/crates.io-index" 2281 | checksum = "7663eacdbd9fbf4a88907ddcfe2e6fa85838eb6dc2418a7d91eebb3786f8e20b" 2282 | dependencies = [ 2283 | "anyhow", 2284 | "bytes", 2285 | "siphasher", 2286 | "uniffi_checksum_derive", 2287 | ] 2288 | 2289 | [[package]] 2290 | name = "uniffi_testing" 2291 | version = "0.28.0" 2292 | source = "registry+https://github.com/rust-lang/crates.io-index" 2293 | checksum = "f922465f7566f25f8fe766920205fdfa9a3fcdc209c6bfb7557f0b5bf45b04dd" 2294 | dependencies = [ 2295 | "anyhow", 2296 | "camino", 2297 | "cargo_metadata", 2298 | "fs-err", 2299 | "once_cell", 2300 | ] 2301 | 2302 | [[package]] 2303 | name = "uniffi_udl" 2304 | version = "0.28.0" 2305 | source = "registry+https://github.com/rust-lang/crates.io-index" 2306 | checksum = "cef408229a3a407fafa4c36dc4f6ece78a6fb258ab28d2b64bddd49c8cb680f6" 2307 | dependencies = [ 2308 | "anyhow", 2309 | "textwrap", 2310 | "uniffi_meta", 2311 | "uniffi_testing", 2312 | "weedle2", 2313 | ] 2314 | 2315 | [[package]] 2316 | name = "universal-hash" 2317 | version = "0.4.1" 2318 | source = "registry+https://github.com/rust-lang/crates.io-index" 2319 | checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" 2320 | dependencies = [ 2321 | "generic-array", 2322 | "subtle", 2323 | ] 2324 | 2325 | [[package]] 2326 | name = "untrusted" 2327 | version = "0.7.1" 2328 | source = "registry+https://github.com/rust-lang/crates.io-index" 2329 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 2330 | 2331 | [[package]] 2332 | name = "url" 2333 | version = "2.5.0" 2334 | source = "registry+https://github.com/rust-lang/crates.io-index" 2335 | checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" 2336 | dependencies = [ 2337 | "form_urlencoded", 2338 | "idna", 2339 | "percent-encoding", 2340 | "serde", 2341 | ] 2342 | 2343 | [[package]] 2344 | name = "utf-8" 2345 | version = "0.7.6" 2346 | source = "registry+https://github.com/rust-lang/crates.io-index" 2347 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 2348 | 2349 | [[package]] 2350 | name = "utf8parse" 2351 | version = "0.2.1" 2352 | source = "registry+https://github.com/rust-lang/crates.io-index" 2353 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 2354 | 2355 | [[package]] 2356 | name = "vcpkg" 2357 | version = "0.2.15" 2358 | source = "registry+https://github.com/rust-lang/crates.io-index" 2359 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2360 | 2361 | [[package]] 2362 | name = "version_check" 2363 | version = "0.9.4" 2364 | source = "registry+https://github.com/rust-lang/crates.io-index" 2365 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 2366 | 2367 | [[package]] 2368 | name = "want" 2369 | version = "0.3.1" 2370 | source = "registry+https://github.com/rust-lang/crates.io-index" 2371 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2372 | dependencies = [ 2373 | "try-lock", 2374 | ] 2375 | 2376 | [[package]] 2377 | name = "wasi" 2378 | version = "0.11.0+wasi-snapshot-preview1" 2379 | source = "registry+https://github.com/rust-lang/crates.io-index" 2380 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2381 | 2382 | [[package]] 2383 | name = "wasm-bindgen" 2384 | version = "0.2.92" 2385 | source = "registry+https://github.com/rust-lang/crates.io-index" 2386 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 2387 | dependencies = [ 2388 | "cfg-if", 2389 | "wasm-bindgen-macro", 2390 | ] 2391 | 2392 | [[package]] 2393 | name = "wasm-bindgen-backend" 2394 | version = "0.2.92" 2395 | source = "registry+https://github.com/rust-lang/crates.io-index" 2396 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 2397 | dependencies = [ 2398 | "bumpalo", 2399 | "log", 2400 | "once_cell", 2401 | "proc-macro2", 2402 | "quote", 2403 | "syn 2.0.57", 2404 | "wasm-bindgen-shared", 2405 | ] 2406 | 2407 | [[package]] 2408 | name = "wasm-bindgen-futures" 2409 | version = "0.4.42" 2410 | source = "registry+https://github.com/rust-lang/crates.io-index" 2411 | checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" 2412 | dependencies = [ 2413 | "cfg-if", 2414 | "js-sys", 2415 | "wasm-bindgen", 2416 | "web-sys", 2417 | ] 2418 | 2419 | [[package]] 2420 | name = "wasm-bindgen-macro" 2421 | version = "0.2.92" 2422 | source = "registry+https://github.com/rust-lang/crates.io-index" 2423 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 2424 | dependencies = [ 2425 | "quote", 2426 | "wasm-bindgen-macro-support", 2427 | ] 2428 | 2429 | [[package]] 2430 | name = "wasm-bindgen-macro-support" 2431 | version = "0.2.92" 2432 | source = "registry+https://github.com/rust-lang/crates.io-index" 2433 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 2434 | dependencies = [ 2435 | "proc-macro2", 2436 | "quote", 2437 | "syn 2.0.57", 2438 | "wasm-bindgen-backend", 2439 | "wasm-bindgen-shared", 2440 | ] 2441 | 2442 | [[package]] 2443 | name = "wasm-bindgen-shared" 2444 | version = "0.2.92" 2445 | source = "registry+https://github.com/rust-lang/crates.io-index" 2446 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 2447 | 2448 | [[package]] 2449 | name = "web-sys" 2450 | version = "0.3.69" 2451 | source = "registry+https://github.com/rust-lang/crates.io-index" 2452 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" 2453 | dependencies = [ 2454 | "js-sys", 2455 | "wasm-bindgen", 2456 | ] 2457 | 2458 | [[package]] 2459 | name = "weedle2" 2460 | version = "5.0.0" 2461 | source = "registry+https://github.com/rust-lang/crates.io-index" 2462 | checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" 2463 | dependencies = [ 2464 | "nom", 2465 | ] 2466 | 2467 | [[package]] 2468 | name = "winapi" 2469 | version = "0.3.9" 2470 | source = "registry+https://github.com/rust-lang/crates.io-index" 2471 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2472 | dependencies = [ 2473 | "winapi-i686-pc-windows-gnu", 2474 | "winapi-x86_64-pc-windows-gnu", 2475 | ] 2476 | 2477 | [[package]] 2478 | name = "winapi-i686-pc-windows-gnu" 2479 | version = "0.4.0" 2480 | source = "registry+https://github.com/rust-lang/crates.io-index" 2481 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2482 | 2483 | [[package]] 2484 | name = "winapi-x86_64-pc-windows-gnu" 2485 | version = "0.4.0" 2486 | source = "registry+https://github.com/rust-lang/crates.io-index" 2487 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2488 | 2489 | [[package]] 2490 | name = "windows-sys" 2491 | version = "0.48.0" 2492 | source = "registry+https://github.com/rust-lang/crates.io-index" 2493 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2494 | dependencies = [ 2495 | "windows-targets 0.48.5", 2496 | ] 2497 | 2498 | [[package]] 2499 | name = "windows-sys" 2500 | version = "0.52.0" 2501 | source = "registry+https://github.com/rust-lang/crates.io-index" 2502 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2503 | dependencies = [ 2504 | "windows-targets 0.52.4", 2505 | ] 2506 | 2507 | [[package]] 2508 | name = "windows-targets" 2509 | version = "0.48.5" 2510 | source = "registry+https://github.com/rust-lang/crates.io-index" 2511 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 2512 | dependencies = [ 2513 | "windows_aarch64_gnullvm 0.48.5", 2514 | "windows_aarch64_msvc 0.48.5", 2515 | "windows_i686_gnu 0.48.5", 2516 | "windows_i686_msvc 0.48.5", 2517 | "windows_x86_64_gnu 0.48.5", 2518 | "windows_x86_64_gnullvm 0.48.5", 2519 | "windows_x86_64_msvc 0.48.5", 2520 | ] 2521 | 2522 | [[package]] 2523 | name = "windows-targets" 2524 | version = "0.52.4" 2525 | source = "registry+https://github.com/rust-lang/crates.io-index" 2526 | checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" 2527 | dependencies = [ 2528 | "windows_aarch64_gnullvm 0.52.4", 2529 | "windows_aarch64_msvc 0.52.4", 2530 | "windows_i686_gnu 0.52.4", 2531 | "windows_i686_msvc 0.52.4", 2532 | "windows_x86_64_gnu 0.52.4", 2533 | "windows_x86_64_gnullvm 0.52.4", 2534 | "windows_x86_64_msvc 0.52.4", 2535 | ] 2536 | 2537 | [[package]] 2538 | name = "windows_aarch64_gnullvm" 2539 | version = "0.48.5" 2540 | source = "registry+https://github.com/rust-lang/crates.io-index" 2541 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2542 | 2543 | [[package]] 2544 | name = "windows_aarch64_gnullvm" 2545 | version = "0.52.4" 2546 | source = "registry+https://github.com/rust-lang/crates.io-index" 2547 | checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" 2548 | 2549 | [[package]] 2550 | name = "windows_aarch64_msvc" 2551 | version = "0.48.5" 2552 | source = "registry+https://github.com/rust-lang/crates.io-index" 2553 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2554 | 2555 | [[package]] 2556 | name = "windows_aarch64_msvc" 2557 | version = "0.52.4" 2558 | source = "registry+https://github.com/rust-lang/crates.io-index" 2559 | checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" 2560 | 2561 | [[package]] 2562 | name = "windows_i686_gnu" 2563 | version = "0.48.5" 2564 | source = "registry+https://github.com/rust-lang/crates.io-index" 2565 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2566 | 2567 | [[package]] 2568 | name = "windows_i686_gnu" 2569 | version = "0.52.4" 2570 | source = "registry+https://github.com/rust-lang/crates.io-index" 2571 | checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" 2572 | 2573 | [[package]] 2574 | name = "windows_i686_msvc" 2575 | version = "0.48.5" 2576 | source = "registry+https://github.com/rust-lang/crates.io-index" 2577 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2578 | 2579 | [[package]] 2580 | name = "windows_i686_msvc" 2581 | version = "0.52.4" 2582 | source = "registry+https://github.com/rust-lang/crates.io-index" 2583 | checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" 2584 | 2585 | [[package]] 2586 | name = "windows_x86_64_gnu" 2587 | version = "0.48.5" 2588 | source = "registry+https://github.com/rust-lang/crates.io-index" 2589 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2590 | 2591 | [[package]] 2592 | name = "windows_x86_64_gnu" 2593 | version = "0.52.4" 2594 | source = "registry+https://github.com/rust-lang/crates.io-index" 2595 | checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" 2596 | 2597 | [[package]] 2598 | name = "windows_x86_64_gnullvm" 2599 | version = "0.48.5" 2600 | source = "registry+https://github.com/rust-lang/crates.io-index" 2601 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2602 | 2603 | [[package]] 2604 | name = "windows_x86_64_gnullvm" 2605 | version = "0.52.4" 2606 | source = "registry+https://github.com/rust-lang/crates.io-index" 2607 | checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" 2608 | 2609 | [[package]] 2610 | name = "windows_x86_64_msvc" 2611 | version = "0.48.5" 2612 | source = "registry+https://github.com/rust-lang/crates.io-index" 2613 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2614 | 2615 | [[package]] 2616 | name = "windows_x86_64_msvc" 2617 | version = "0.52.4" 2618 | source = "registry+https://github.com/rust-lang/crates.io-index" 2619 | checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" 2620 | 2621 | [[package]] 2622 | name = "winreg" 2623 | version = "0.50.0" 2624 | source = "registry+https://github.com/rust-lang/crates.io-index" 2625 | checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" 2626 | dependencies = [ 2627 | "cfg-if", 2628 | "windows-sys 0.48.0", 2629 | ] 2630 | 2631 | [[package]] 2632 | name = "zerocopy" 2633 | version = "0.7.35" 2634 | source = "registry+https://github.com/rust-lang/crates.io-index" 2635 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 2636 | dependencies = [ 2637 | "zerocopy-derive", 2638 | ] 2639 | 2640 | [[package]] 2641 | name = "zerocopy-derive" 2642 | version = "0.7.35" 2643 | source = "registry+https://github.com/rust-lang/crates.io-index" 2644 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 2645 | dependencies = [ 2646 | "proc-macro2", 2647 | "quote", 2648 | "syn 2.0.57", 2649 | ] 2650 | 2651 | [[package]] 2652 | name = "zeroize" 2653 | version = "1.7.0" 2654 | source = "registry+https://github.com/rust-lang/crates.io-index" 2655 | checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" 2656 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pbcli" 3 | description = """ 4 | pbcli is a command line client which allows to upload and download 5 | pastes from privatebin directly from the command line. 6 | """ 7 | version = "2.8.0" 8 | authors = ["Mydayyy"] 9 | edition = "2021" 10 | documentation = "https://github.com/Mydayyy/pbcli" 11 | homepage = "https://github.com/Mydayyy/pbcli" 12 | repository = "https://github.com/Mydayyy/pbcli" 13 | keywords = ["privatebin", "pastebin", "pasteservice"] 14 | categories = ["command-line-utilities"] 15 | license = "Unlicense OR MIT" 16 | 17 | [lib] 18 | crate-type = ["lib", "cdylib", "staticlib"] 19 | name = "pbcli" 20 | 21 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 22 | 23 | [dependencies] 24 | clap = { version = "4.5.29", features = ["derive"] } 25 | reqwest = { version = "0.12", features = ["blocking", "json"] } 26 | serde = { version = "1.0.130", features = ["derive"] } 27 | serde_json = "1.0.69" 28 | serde_with = "1" 29 | miniz_oxide = "0.5.0" 30 | ring = "0.16" 31 | aes-gcm = { version = "0.9.4", features = ["aes"] } 32 | bs58 = "0.4.0" 33 | base64 = "0.13" 34 | typenum = "1.14.0" 35 | hex-literal = "0.3.3" 36 | pbkdf2 = "0.9.0" 37 | rand_core = { version = "0.6.3", features = ["std"] } 38 | crypto-mac = "0.11.1" 39 | hmac = "0.11.0" 40 | sha2 = "0.9.8" 41 | url = { version = "2.2.2", features = ["serde"] } 42 | rand_chacha = "0.3.1" 43 | dialoguer = "0.9.0" 44 | data-url = "0.1.1" 45 | mime_guess = "2.0.3" 46 | terminal_size = "0.1.17" 47 | parse-size = { version = "1.0.0", features = ["std"] } 48 | uniffi = { version = "0.28.0", optional = true, features = ["cli"] } 49 | openssl = { version = "0.10", features = ["vendored"] } 50 | directories = "5.0.1" 51 | log = "0.4.22" 52 | scraper = "0.21.0" 53 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Mydayyy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /LICENSE-UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Privatebin CLI 2 | ------------ 3 | pbcli is a command line client which allows to upload and download 4 | pastes from privatebin directly from the command line. 5 | 6 | It is dual licensed under MIT or the [UNLICENSE](https://unlicense.org). 7 | 8 | ### Table of Contents 9 | 10 | * [Installation](#Installation) 11 | * [Building](#Building) 12 | * [User Guide](#User-Guide) 13 | * [Configuration Files](#Configuration-File) 14 | * [Roadmap](#Roadmap) 15 | 16 | ### Installation 17 | 18 | You can find pre-compiled binaries under the release tab in github. 19 | 20 | For Archlinux, it is [available inside the AUR](https://aur.archlinux.org/packages/pbcli/). 21 | 22 | ### Building 23 | 24 | pbcli is written in Rust, so you will need a rust toolchain to 25 | build it. 26 | 27 | ``` 28 | git clone https://github.com/Mydayyy/pbcli.git 29 | cd pbcli 30 | cargo build --release 31 | ./target/release/pbcli --version 32 | ``` 33 | 34 | ### User Guide 35 | 36 | pbcli is simple to use and only involves a few flags. The only 37 | needed argument is either the positional argument `URL` or the option flag 38 | `host`. If both are provided the positional argument URL takes 39 | precedence. To avoid specifying the host / url everytime you can 40 | take advantage of a config file as described [here](#Configuration-File). 41 | 42 | When posting a paste you can specify `--json` to receive post details. The output 43 | includes the base58 encoded key used to encrypt/decrypt the paste. 44 | Constructed paste url (including key) and delete url (including token) are also provided for convenience. 45 | 46 | Example output: 47 | 48 | ```json 49 | { 50 | "baseurl": "https://privatebin.net/", 51 | "bs58key": "GN3qty1kAFbsGi9FbKKXigXwux1eofhiZQXNVFRMrNQd", 52 | "deletetoken": "8536f6f8310ed4a9aae0e111b1763f5851cdbefe4c35e4b96bd690269635354a", 53 | "deleteurl": "https://privatebin.net/?pasteid=31e2e7b19481fa7d&deletetoken=8536f6f8310ed4a9aae0e111b1763f5851cdbefe4c35e4b96bd690269635354a", 54 | "id": "31e2e7b19481fa7d", 55 | "pasteurl": "https://privatebin.net/?31e2e7b19481fa7d#GN3qty1kAFbsGi9FbKKXigXwux1eofhiZQXNVFRMrNQd", 56 | "status": 0, 57 | "url": "/?31e2e7b19481fa7d" 58 | } 59 | ``` 60 | 61 | --- 62 | 63 | #### Example usages to get a paste: 64 | 65 | ``` 66 | pbcli https://privatebin.net/?f37ca34e72e2ef77#G8wFGVnpSb4pogzGbMMcgbDgeYkQ5cfcWkcsVwTQJmzd 67 | ``` 68 | 69 | ``` 70 | pbcli --host https://privatebin.net/?f37ca34e72e2ef77#G8wFGVnpSb4pogzGbMMcgbDgeYkQ5cfcWkcsVwTQJmzd 71 | ``` 72 | 73 | --- 74 | 75 | #### Example usages to post a new poste 76 | 77 | ``` 78 | echo 'TestPaste' | pbcli --host https://privatebin.net/ 79 | ``` 80 | 81 | ``` 82 | echo 'TestPaste' | pbcli https://privatebin.net/ --json 83 | ``` 84 | 85 | ``` 86 | echo 'TestPaste' | pbcli --host https://privatebin.net/ --expire=1hour 87 | ``` 88 | 89 | ``` 90 | echo '## Title\nSome Markdown' | pbcli https://privatebin.net/ --format markdown 91 | ``` 92 | 93 | ``` 94 | echo 'TestPaste' | pbcli --host https://privatebin.net/ --burn 95 | ``` 96 | 97 | --- 98 | 99 | #### CLI Help: 100 | 101 | ``` 102 | pbcli is a command line client which allows to upload and download 103 | pastes from privatebin directly from the command line. 104 | 105 | Project home page: https://github.com/Mydayyy/pbcli 106 | 107 | Usage: pbcli [OPTIONS] [URL] 108 | 109 | Arguments: 110 | [URL] 111 | 112 | Options: 113 | --host 114 | -f, --format [default: plaintext] [possible values: plaintext, syntax, markdown] 115 | -e, --expire [default: 1week] 116 | --size-limit Prompt if the paste exceeds the given size. Fail in non-interactive environments. 117 | --json richer output: for delete_url, comments, etc 118 | -b, --burn enable burn on read for new paste 119 | -B, --no-burn disable burn if set 120 | -d, --discussion enable discussion for new paste 121 | -D, --no-discussion disable burn if set 122 | --comment make new comment on existing paste 123 | --comment-as use this nick for comment 124 | --comment-to reply to this parent comment 125 | -o, --download 126 | -w, --overwrite overwrite the file given with --download if it already exists 127 | -u, --upload 128 | -p, --password 129 | --oidc-token-url oidc token endpoint from which to obtain an access token 130 | --oidc-client-id client id to send to the token endpoint 131 | --oidc-username username to send to the token endpoint 132 | --oidc-password password to send to the token endpoint 133 | --debug print debug output to stderr 134 | --no-default-config do not look for config in default locations 135 | --scrape-expiries attempt scraping supported expiries of given host and exit 136 | -h, --help Print help 137 | -V, --version Print version 138 | ``` 139 | 140 | ### Configuration File 141 | 142 | pbcli supports a configuration file to fine tune the default behaviour. 143 | You need to set the environment variable `PBCLI_CONFIG_PATH` to a file path. The file 144 | needs to contain flags you want to pass to pbcli, one per line. 145 | Lines starting with a # are ignored. An useful case for this may be 146 | setting a default instance to use by setting the --host argument. 147 | 148 | Additionally, pbcli will look in a few default directories to find a config. This can be disabled 149 | via the `--no-default-config` argument. The directories it checks are: 150 | 151 | - `$XDG_CONFIG_HOME/pbcli/config` if the XDG variable is set. Otherwise `$HOME/.config/pbcli/config` 152 | - /etc/pbcli/config 153 | 154 | As well as the windows and mac equivalents to those linux paths. Details can be found 155 | here: https://docs.rs/directories/latest/directories/struct.ProjectDirs.html#method.config_local_dir 156 | 157 | The debug mode can be used to troubleshoot config loading issues. It will print the used config as well 158 | as the directories that were searched for a config. 159 | 160 | Instead of typing `echo 'test' | pbcli https://privatebin.net/` you'll only need 161 | to type `echo 'test' | pbcli` 162 | 163 | Example config: 164 | 165 | ``` 166 | --host=https://privatebin.net/ 167 | --expire=1month 168 | ``` 169 | 170 | ### Uniffi 171 | 172 | This projects offers uniffi bindings. In order to enable them, 173 | build the library with the uniffi feature enabled. 174 | You can learn more about uniffi [here](https://github.com/mozilla/uniffi-rs). 175 | Additionally to see an example integration of pbcli with uniffi 176 | enabled into an android project you can check out [sharepaste](https://github.com/nain-F49FF806/sharepaste.oo). 177 | 178 | ### Roadmap 179 | 180 | - Descriptive error messages 181 | - Add support for auth mechanism 182 | - Basic auth 183 | - ~~oauth~~ Added in v2.2.0 using Resource Owner Password Credential Grant flow 184 | - ~~Add support for file attachments~~ Added in v2.1.0 185 | 186 | ### Credits 187 | 188 | - [nain](https://github.com/nain-F49FF806) for the uniffi implementation 189 | -------------------------------------------------------------------------------- /src/api.rs: -------------------------------------------------------------------------------- 1 | use crate::crypto::{encrypt, Decryptable}; 2 | use crate::error::{PasteError, PbError, PbResult}; 3 | use crate::opts::Opts; 4 | use crate::privatebin::{Comment, DecryptedComment, Paste, PostCommentResponse, PostPasteResponse}; 5 | use crate::util::check_filesize; 6 | use crate::DecryptedPaste; 7 | use rand_chacha::rand_core::{RngCore, SeedableRng}; 8 | use reqwest::{Method, Url}; 9 | use scraper::{Html, Selector}; 10 | use std::str::FromStr; 11 | 12 | #[cfg_attr(feature = "uniffi", derive(uniffi::Object))] 13 | pub struct API { 14 | base: Url, 15 | opts: Opts, 16 | } 17 | 18 | #[cfg_attr(feature = "uniffi", uniffi::export)] 19 | impl API { 20 | #[cfg_attr(feature = "uniffi", uniffi::constructor)] 21 | pub fn new(mut url: Url, opts: Opts) -> Self { 22 | url.set_fragment(None); 23 | url.set_query(None); 24 | if !url.path().ends_with('/') { 25 | url.set_path(&format!("{}{}", url.path(), "/")) 26 | } 27 | Self { base: url, opts } 28 | } 29 | } 30 | 31 | impl API { 32 | fn get_oidc_access_token(&self) -> PbResult { 33 | let oidc_token_endpoint = self.opts.oidc_token_url.as_ref().unwrap(); 34 | let oidc_client_id = self.opts.oidc_client_id.as_ref().unwrap(); 35 | let oidc_username = self.opts.oidc_username.as_ref().unwrap(); 36 | let oidc_password = self.opts.oidc_password.as_ref().unwrap(); 37 | 38 | let mut post_fields = std::collections::HashMap::new(); 39 | post_fields.insert("grant_type", "password"); 40 | post_fields.insert("client_id", oidc_client_id); 41 | post_fields.insert("username", oidc_username); 42 | post_fields.insert("password", oidc_password); 43 | 44 | let client = reqwest::blocking::Client::builder().build()?; 45 | let mut request = client.post(oidc_token_endpoint); 46 | request = request.form(&post_fields); 47 | 48 | let response = request.send()?; 49 | 50 | if response.status().as_u16() != 200 { 51 | return Err(PbError::OidcBadRequest(response.json()?)); 52 | } 53 | 54 | let access_token_response: serde_json::Value = response.json()?; 55 | 56 | let token_type = access_token_response 57 | .get("token_type") 58 | .unwrap() 59 | .as_str() 60 | .unwrap(); 61 | if !token_type.eq_ignore_ascii_case("bearer") { 62 | return Err(PbError::InvalidTokenType(token_type.to_string())); 63 | } 64 | 65 | let token: String = access_token_response 66 | .get("access_token") 67 | .unwrap() 68 | .as_str() 69 | .unwrap() 70 | .to_string(); 71 | 72 | Ok(token) 73 | } 74 | 75 | fn preconfigured_privatebin_request_builder( 76 | &self, 77 | method: &str, 78 | url: Url, 79 | json_request: bool, 80 | ) -> PbResult { 81 | let client = reqwest::blocking::Client::builder().build()?; 82 | 83 | let mut request = client.request(Method::from_str(method).unwrap(), url); 84 | if json_request { 85 | request = request.header("X-Requested-With", "JSONHttpRequest"); 86 | } 87 | 88 | if self.opts.oidc_token_url.is_some() { 89 | let access_token = self.get_oidc_access_token()?; 90 | let auth_header = ["Bearer".into(), access_token].join(" "); 91 | request = request.header("Authorization", auth_header) 92 | } 93 | 94 | Ok(request) 95 | } 96 | } 97 | 98 | #[cfg_attr(feature = "uniffi", uniffi::export)] 99 | impl API { 100 | pub fn get_paste(&self, paste_id: &str) -> PbResult { 101 | let url = reqwest::Url::parse_with_params(self.base.as_str(), [("pasteid", paste_id)])?; 102 | let value: serde_json::Value = self 103 | .preconfigured_privatebin_request_builder("GET", url, true)? 104 | .send()? 105 | .json()?; 106 | let status: u32 = value.get("status").unwrap().as_u64().unwrap() as u32; 107 | 108 | match status { 109 | 0 => Ok(serde_json::from_value(value)?), 110 | 1 => Err(PasteError::PasteNotFound), 111 | s => Err(PasteError::UnknownPasteStatus(s)), 112 | } 113 | } 114 | 115 | pub fn post_paste( 116 | &self, 117 | content: &DecryptedPaste, 118 | password: &str, 119 | opts: &Opts, 120 | ) -> PbResult { 121 | let mut rng = rand_chacha::ChaCha20Rng::from_entropy(); 122 | let mut paste_passphrase = [0u8; 32]; 123 | rng.fill_bytes(&mut paste_passphrase); 124 | 125 | let mut paste = Paste { 126 | v: 2, 127 | ..Default::default() 128 | }; 129 | paste.adata.format = opts.format; 130 | paste.adata.discuss = opts.discussion as u8; 131 | paste.adata.burn = opts.burn as u8; 132 | paste.meta.expire = Some(opts.expire.clone()); 133 | 134 | let cipher = &paste.adata.cipher; 135 | 136 | let encrypted_content = encrypt( 137 | &serde_json::to_string(content)?, 138 | &paste_passphrase, 139 | password, 140 | &cipher.vec_kdf_salt()?, 141 | &cipher.vec_cipher_iv()?, 142 | cipher.kdf_iterations, 143 | &paste.get_adata_str(), 144 | )?; 145 | 146 | let b64_encrpyed_content = base64::encode(encrypted_content); 147 | check_filesize(b64_encrpyed_content.len() as u64, opts.size_limit); 148 | paste.ct = b64_encrpyed_content; 149 | 150 | let url = self.base.clone(); 151 | let response = self 152 | .preconfigured_privatebin_request_builder("POST", url, true)? 153 | .body::(serde_json::to_string(&paste).unwrap()) 154 | .send()?; 155 | let mut rsv: serde_json::Value = response.json()?; 156 | rsv["bs58key"] = serde_json::Value::String(bs58::encode(paste_passphrase).into_string()); 157 | rsv["baseurl"] = serde_json::Value::String(self.base.to_string()); 158 | let status: u32 = rsv.get("status").unwrap().as_u64().unwrap() as u32; 159 | 160 | match status { 161 | 0 => Ok(serde_json::from_value::(rsv)?), 162 | 1 => Err(PasteError::InvalidData), 163 | s => Err(PasteError::UnknownPasteStatus(s)), 164 | } 165 | } 166 | 167 | pub fn post_comment( 168 | &self, 169 | content: &DecryptedComment, 170 | paste_id: &str, 171 | parent_id: &str, 172 | bs58key: &str, 173 | password: &str, 174 | opts: &Opts, 175 | ) -> PbResult { 176 | let mut comment = Comment { 177 | v: 2, 178 | pasteid: paste_id.into(), 179 | parentid: parent_id.into(), 180 | ..Default::default() 181 | }; 182 | let cipher = &comment.adata; 183 | let paste_passphrase = bs58::decode(bs58key).into_vec()?; 184 | 185 | let encrypted_content = encrypt( 186 | &serde_json::to_string(content)?, 187 | &paste_passphrase, 188 | password, 189 | &cipher.vec_kdf_salt()?, 190 | &cipher.vec_cipher_iv()?, 191 | cipher.kdf_iterations, 192 | &comment.get_adata_str(), 193 | )?; 194 | 195 | let b64_encrpyed_content = base64::encode(encrypted_content); 196 | check_filesize(b64_encrpyed_content.len() as u64, opts.size_limit); 197 | comment.ct = b64_encrpyed_content; 198 | 199 | let url = self.base.clone(); 200 | let response = self 201 | .preconfigured_privatebin_request_builder("POST", url, true)? 202 | .body::(serde_json::to_string(&comment).unwrap()) 203 | .send()?; 204 | let rsv: serde_json::Value = response.json()?; 205 | let status: u32 = rsv.get("status").unwrap().as_u64().unwrap() as u32; 206 | 207 | match status { 208 | 0 => Ok(serde_json::from_value::(rsv)?), 209 | 1 => Err(PasteError::InvalidData), 210 | s => Err(PasteError::UnknownPasteStatus(s)), 211 | } 212 | } 213 | 214 | pub fn scrape_expiries(&self) -> PbResult> { 215 | let url = self.base.clone(); 216 | let response = self 217 | .preconfigured_privatebin_request_builder("GET", url, false)? 218 | .send()?; 219 | response.error_for_status_ref()?; 220 | let html = response.text()?; 221 | let document = Html::parse_document(&html); 222 | let expiries_selector = Selector::parse("#expiration + ul > li > a").unwrap(); 223 | let mut expiries = Vec::new(); 224 | for expiry_anchor in document.select(&expiries_selector) { 225 | if let Some(expiry) = expiry_anchor.attr("data-expiration") { 226 | expiries.push(expiry.to_string()); 227 | } 228 | } 229 | Ok(expiries) 230 | } 231 | 232 | pub fn base(&self) -> Url { 233 | self.base.clone() 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::ffi::OsString; 3 | use std::io::BufRead; 4 | use std::path::{Path, PathBuf}; 5 | 6 | fn is_valid_config(p: &Path) -> bool { 7 | log::debug!("looking for config at {}", p.display()); 8 | p.exists() && p.is_file() 9 | } 10 | 11 | fn get_config_path(skip_default_locations: bool) -> Option { 12 | // check if config env var is set and use it 13 | if let Some(path) = env::var_os("PBCLI_CONFIG_PATH") { 14 | log::debug!("using config pointed to by PBCLI_CONFIG_PATH"); 15 | return Some(path); 16 | }; 17 | 18 | log::debug!("PBCLI_CONFIG_PATH not set"); 19 | 20 | if skip_default_locations { 21 | log::debug!("skip_default_locations set. not checking default config locations"); 22 | return None; 23 | } 24 | 25 | // check user specific config location 26 | let project_dirs = directories::ProjectDirs::from("eu", "mydayyy", env!("CARGO_PKG_NAME"))?; 27 | let user_config_dir = project_dirs.config_local_dir(); 28 | let user_config_file = user_config_dir.join("config"); 29 | if is_valid_config(&user_config_file) { 30 | return Some(user_config_file.into()); 31 | } 32 | 33 | // linux only: check /etc/pbcli/config 34 | if cfg!(unix) { 35 | let system_config_file = PathBuf::from("/etc/pbcli/config"); 36 | if is_valid_config(&system_config_file) { 37 | return Some(system_config_file.into()); 38 | } 39 | } 40 | 41 | None 42 | } 43 | 44 | pub fn get_config_args(skip_default_locations: bool) -> Vec { 45 | let path = match get_config_path(skip_default_locations) { 46 | None => { 47 | log::debug!("no config found"); 48 | return vec![]; 49 | } 50 | Some(path) => path, 51 | }; 52 | 53 | log::debug!("using config {}", path.to_string_lossy()); 54 | 55 | let handle = match std::fs::File::open(path) { 56 | Ok(file) => file, 57 | Err(_) => { 58 | log::debug!("failed to open config. using cli args only"); 59 | return vec![]; 60 | } // TODO: Raise error 61 | }; 62 | 63 | let reader = std::io::BufReader::new(handle); 64 | let mut config_args: Vec = vec![]; 65 | reader.lines().for_each(|line| { 66 | let line = match line { 67 | Ok(line) => line.trim().to_owned(), 68 | Err(_) => return, 69 | }; 70 | 71 | if line.starts_with('#') { 72 | return; 73 | } 74 | 75 | if line.is_empty() { 76 | return; 77 | } 78 | 79 | if line.chars().all(char::is_whitespace) { 80 | return; 81 | } 82 | 83 | config_args.push(line.into()); 84 | }); 85 | 86 | config_args 87 | } 88 | 89 | pub fn get_cli_args() -> Vec { 90 | std::env::args_os().collect() 91 | } 92 | 93 | fn has_flag(flag_name: &str) -> bool { 94 | get_cli_args().contains(&OsString::from(flag_name)) 95 | } 96 | pub fn has_debug_flag() -> bool { 97 | has_flag("--debug") 98 | } 99 | 100 | pub fn has_skip_default_config_flag() -> bool { 101 | has_flag("--skip-default-config") 102 | } 103 | -------------------------------------------------------------------------------- /src/crypto.rs: -------------------------------------------------------------------------------- 1 | use crate::error::{PasteError, PbResult}; 2 | use crate::privatebin::{Cipher, CompressionType}; 3 | use aes_gcm::aead::{Aead, NewAead}; 4 | use aes_gcm::{Key, Nonce}; 5 | 6 | /// Trait implemented by any decrypt-able type (paste or comment) 7 | pub trait Decryptable { 8 | /// Get ciphertext. 9 | /// We prefer to borrow this and not copy, because ct may be large. 10 | fn get_ct(&self) -> &str; 11 | /// Additional authenticated (but not encrypted) data. 12 | /// Sensitive to formatting changes. 13 | fn get_adata_str(&self) -> String; 14 | /// Cipher parameters 15 | fn get_cipher(&self) -> &Cipher; 16 | } 17 | 18 | fn derive_key(iterations: std::num::NonZeroU32, salt: &[u8], key: &[u8], out: &mut [u8]) { 19 | ring::pbkdf2::derive(ring::pbkdf2::PBKDF2_HMAC_SHA256, iterations, salt, key, out); 20 | } 21 | 22 | /// Decrypt decryptable, then attempt deserialize to requested type (DecryptedT) 23 | pub fn decrypt_with_password( 24 | decryptable: &impl Decryptable, 25 | key: &[u8], 26 | password: &str, 27 | ) -> PbResult { 28 | let cipher_algo = &decryptable.get_cipher().cipher_algo; 29 | let cipher_mode = &decryptable.get_cipher().cipher_mode; 30 | let kdf_keysize = decryptable.get_cipher().kdf_keysize; 31 | let compression_type = &decryptable.get_cipher().compression_type; 32 | 33 | let salt = &decryptable.get_cipher().vec_kdf_salt()?; 34 | let iterations = std::num::NonZeroU32::new(decryptable.get_cipher().kdf_iterations).unwrap(); 35 | 36 | let key = [key, password.as_bytes()].concat(); 37 | 38 | let mut derived_key = [0u8; 32]; 39 | derive_key(iterations, salt, &key, &mut derived_key); 40 | 41 | match (&cipher_algo[..], &cipher_mode[..], kdf_keysize) { 42 | ("aes", "gcm", 256) => { 43 | let data = decrypt_aes_256_gcm(decryptable, &derived_key, compression_type)?; 44 | let value: serde_json::Value = serde_json::from_slice(&data)?; 45 | Ok(serde_json::from_value(value)?) 46 | } 47 | _ => Err(PasteError::CipherNotImplemented { 48 | cipher_mode: decryptable.get_cipher().cipher_mode.clone(), 49 | cipher_algo: decryptable.get_cipher().cipher_algo.clone(), 50 | keysize: decryptable.get_cipher().kdf_keysize, 51 | }), 52 | } 53 | } 54 | 55 | pub fn encrypt( 56 | content: &str, 57 | key: &[u8], 58 | password: &str, 59 | salt: &[u8], 60 | nonce: &[u8], 61 | iterations: u32, 62 | aad: &str, 63 | ) -> PbResult> { 64 | let paste_blob = miniz_oxide::deflate::compress_to_vec(content.as_bytes(), 10); 65 | 66 | let key = [key, password.as_bytes()].concat(); 67 | 68 | let mut derived_key = [0u8; 32]; 69 | derive_key( 70 | std::num::NonZeroU32::new(iterations).unwrap(), 71 | salt, 72 | &key, 73 | &mut derived_key, 74 | ); 75 | 76 | type Cipher = aes_gcm::AesGcm; 77 | let cipher = Cipher::new(Key::from_slice(&derived_key)); 78 | let payload = aes_gcm::aead::Payload { 79 | msg: &paste_blob, 80 | aad: aad.as_bytes(), 81 | }; 82 | let encrypted_data = cipher.encrypt(Nonce::from_slice(nonce), payload)?; 83 | 84 | Ok(encrypted_data) 85 | } 86 | 87 | fn decrypt_aes_256_gcm( 88 | decryptable: &impl Decryptable, 89 | derived_key: &[u8], 90 | compression_type: &CompressionType, 91 | ) -> PbResult> { 92 | type Cipher = aes_gcm::AesGcm; 93 | let ciphertext = base64::decode(decryptable.get_ct())?; 94 | let nonce = decryptable.get_cipher().vec_cipher_iv()?; 95 | 96 | let cipher = Cipher::new(Key::from_slice(derived_key)); 97 | let adata_str = decryptable.get_adata_str(); 98 | let payload = aes_gcm::aead::Payload { 99 | msg: &ciphertext, 100 | aad: adata_str.as_bytes(), 101 | }; 102 | let data = cipher.decrypt(Nonce::from_slice(&nonce), payload)?; 103 | let decompressed = match compression_type { 104 | CompressionType::None => data, 105 | CompressionType::Zlib => miniz_oxide::inflate::decompress_to_vec(&data)?, 106 | }; 107 | Ok(decompressed) 108 | } 109 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use base64::DecodeError; 2 | use data_url::DataUrlError; 3 | use log::SetLoggerError; 4 | use miniz_oxide::inflate::TINFLStatus; 5 | use serde_json::Error; 6 | use std::fmt; 7 | use std::fmt::Formatter; 8 | 9 | pub type PbError = PasteError; 10 | pub type PbResult = std::result::Result; 11 | 12 | #[derive(Debug)] 13 | #[cfg_attr(feature = "uniffi", derive(uniffi::Error))] 14 | #[cfg_attr(feature = "uniffi", uniffi(flat_error))] 15 | pub enum PasteError { 16 | CipherNotImplemented { 17 | cipher_algo: String, 18 | cipher_mode: String, 19 | keysize: u32, 20 | }, 21 | MissingDecryptionKey, 22 | // BadUrl, 23 | PasteNotFound, 24 | InvalidData, 25 | UnknownPasteStatus(u32), 26 | Json(serde_json::error::Error), 27 | Request(reqwest::Error), 28 | Io(std::io::Error), 29 | ParseError(url::ParseError), 30 | Base64Error(DecodeError), 31 | Base58Error(bs58::decode::Error), 32 | Aes(aes_gcm::Error), 33 | Zlib(miniz_oxide::inflate::TINFLStatus), 34 | InvalidAttachment(data_url::DataUrlError), 35 | FileExists, 36 | NotAFile, 37 | InvalidTokenType(String), 38 | OidcBadRequest(serde_json::Value), 39 | LoggerInit(log::SetLoggerError), 40 | } 41 | 42 | impl std::error::Error for PasteError {} 43 | 44 | impl fmt::Display for PasteError { 45 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 46 | match self { 47 | PasteError::CipherNotImplemented { 48 | cipher_algo, 49 | cipher_mode, 50 | keysize, 51 | } => write!( 52 | f, 53 | "Cipher not implemented algo: {} mode: {} keysize: {}", 54 | cipher_algo, cipher_mode, keysize 55 | ), 56 | PasteError::Json(r) => r.fmt(f), 57 | PasteError::Request(r) => r.fmt(f), 58 | PasteError::Io(r) => r.fmt(f), 59 | PasteError::ParseError(r) => r.fmt(f), 60 | PasteError::Base64Error(r) => r.fmt(f), 61 | PasteError::Aes(err) => err.fmt(f), 62 | PasteError::Zlib(err) => write!(f, "Zlib error: {:?}", err), 63 | PasteError::Base58Error(err) => err.fmt(f), 64 | PasteError::UnknownPasteStatus(err) => write!(f, "Unknown paste status: {}", err), 65 | PasteError::PasteNotFound => write!(f, "Invalid paste ID"), 66 | PasteError::MissingDecryptionKey => write!(f, "Missing decryption key"), 67 | // PasteError::BadUrl => write!(f, "Badly formatted url"), 68 | PasteError::InvalidData => write!(f, "Invalid Data"), 69 | PasteError::InvalidAttachment(err) => write!(f, "Invalid attachment: {:?}", err), 70 | PasteError::FileExists => write!(f, "File already exists. Use --overwrite to force"), 71 | PasteError::NotAFile => write!(f, "Given path is not a file"), 72 | PasteError::InvalidTokenType(token_type) => { 73 | write!(f, "Invalid token type: {}", token_type) 74 | } 75 | PasteError::OidcBadRequest(json) => write!(f, "{}", json), 76 | PasteError::LoggerInit(err) => { 77 | write!(f, "Failed to init logger: {}", err) 78 | } 79 | } 80 | } 81 | } 82 | 83 | impl From for PasteError { 84 | fn from(err: std::io::Error) -> Self { 85 | PasteError::Io(err) 86 | } 87 | } 88 | 89 | impl From for PasteError { 90 | fn from(err: Error) -> Self { 91 | PasteError::Json(err) 92 | } 93 | } 94 | 95 | impl From for PasteError { 96 | fn from(err: url::ParseError) -> Self { 97 | PasteError::ParseError(err) 98 | } 99 | } 100 | 101 | impl From for PasteError { 102 | fn from(err: reqwest::Error) -> Self { 103 | PasteError::Request(err) 104 | } 105 | } 106 | 107 | impl From for PasteError { 108 | fn from(err: DecodeError) -> Self { 109 | PasteError::Base64Error(err) 110 | } 111 | } 112 | 113 | impl From for PasteError { 114 | fn from(err: aes_gcm::Error) -> Self { 115 | PasteError::Aes(err) 116 | } 117 | } 118 | 119 | impl From for PasteError { 120 | fn from(err: TINFLStatus) -> Self { 121 | PasteError::Zlib(err) 122 | } 123 | } 124 | 125 | impl From for PasteError { 126 | fn from(err: bs58::decode::Error) -> Self { 127 | PasteError::Base58Error(err) 128 | } 129 | } 130 | 131 | impl From for PasteError { 132 | fn from(err: DataUrlError) -> Self { 133 | PasteError::InvalidAttachment(err) 134 | } 135 | } 136 | 137 | impl From for PasteError { 138 | fn from(err: SetLoggerError) -> Self { 139 | PasteError::LoggerInit(err) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod api; 2 | pub mod config; 3 | pub mod crypto; 4 | pub mod error; 5 | pub mod opts; 6 | pub mod privatebin; 7 | pub mod util; 8 | 9 | #[cfg(feature = "uniffi")] 10 | mod uniffi_custom_types; 11 | 12 | pub use api::API; 13 | pub use error::{PasteError, PbResult}; 14 | pub use opts::Opts; 15 | pub use privatebin::{DecryptedPaste, PasteFormat}; 16 | pub use util::check_filesize; 17 | 18 | #[cfg(feature = "uniffi")] 19 | uniffi::setup_scaffolding!(); 20 | -------------------------------------------------------------------------------- /src/logger.rs: -------------------------------------------------------------------------------- 1 | use log::{Metadata, Record}; 2 | 3 | pub(crate) struct SimpleLogger(()); 4 | const LOGGER: &SimpleLogger = &SimpleLogger(()); 5 | 6 | impl SimpleLogger { 7 | pub(crate) fn init() -> Result<(), log::SetLoggerError> { 8 | log::set_logger(LOGGER) 9 | } 10 | } 11 | 12 | impl log::Log for SimpleLogger { 13 | fn enabled(&self, _metadata: &Metadata) -> bool { 14 | true 15 | } 16 | 17 | fn log(&self, record: &Record) { 18 | if self.enabled(record.metadata()) { 19 | eprintln!("{} {}: {}", record.level(), record.target(), record.args()); 20 | } 21 | } 22 | 23 | fn flush(&self) {} 24 | } 25 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use data_url::DataUrl; 3 | use pbcli::api::API; 4 | use pbcli::error::{PasteError, PbResult}; 5 | use pbcli::opts::Opts; 6 | use pbcli::privatebin::{DecryptedComment, DecryptedCommentsMap, DecryptedPaste}; 7 | use pbcli::util::check_filesize; 8 | use serde_json::Value; 9 | use std::ffi::OsString; 10 | use std::io::IsTerminal; 11 | use std::io::{Read, Write}; 12 | 13 | mod logger; 14 | 15 | fn get_stdin() -> std::io::Result { 16 | if std::io::stdin().is_terminal() { 17 | return Ok("".into()); 18 | } 19 | let mut buffer = String::new(); 20 | std::io::stdin().read_to_string(&mut buffer)?; 21 | Ok(buffer) 22 | } 23 | 24 | fn create_dataurl(path: &std::ffi::OsStr, data: String) -> String { 25 | let mime = mime_guess::from_path(path) 26 | .first() 27 | .unwrap_or(mime_guess::mime::APPLICATION_OCTET_STREAM); 28 | format!("data:{};base64,{}", mime.essence_str(), data) 29 | } 30 | 31 | fn handle_get(opts: &Opts) -> PbResult<()> { 32 | let url = opts.get_url(); 33 | let paste_id = opts.get_url().query().unwrap(); 34 | let fragment = opts 35 | .get_url() 36 | .fragment() 37 | .ok_or(PasteError::MissingDecryptionKey)?; 38 | // '-' character may be found at start of fragment. This should be stripped. 39 | // It is used to activate "warn before read" feature for burn on read pastes. 40 | let key = fragment.strip_prefix('-').unwrap_or(fragment); 41 | 42 | let api = API::new(url.clone(), opts.clone()); 43 | let paste = api.get_paste(paste_id)?; 44 | 45 | let content: DecryptedPaste; 46 | let comments: DecryptedCommentsMap; 47 | 48 | if let Some(pass) = &opts.password { 49 | content = paste.decrypt_with_password(key, pass)?; 50 | comments = paste.decrypt_comments_with_password(key, pass)?; 51 | } else { 52 | match paste.decrypt(key) { 53 | Ok(c) => { 54 | content = c; 55 | comments = paste.decrypt_comments(key)?; 56 | } 57 | Err(err) => { 58 | if !std::io::stdin().is_terminal() { 59 | return Err(err); 60 | } 61 | 62 | let password = dialoguer::Password::new() 63 | .with_prompt("Enter password") 64 | .interact()?; 65 | content = paste.decrypt_with_password(key, &password)?; 66 | comments = paste.decrypt_comments_with_password(key, &password)?; 67 | } 68 | } 69 | } 70 | 71 | if content.attachment.is_some() && opts.download.is_some() { 72 | let attachment = content.attachment.as_ref().unwrap(); 73 | let outfile = opts.download.as_ref().unwrap(); 74 | 75 | let url = DataUrl::process(attachment)?; 76 | let (body, _) = url.decode_to_vec().unwrap(); 77 | 78 | if outfile.exists() && !opts.overwrite { 79 | return Err(PasteError::FileExists); 80 | } 81 | 82 | let mut handle = std::fs::File::create(outfile)?; 83 | 84 | handle.write_all(&body)?; 85 | } 86 | 87 | if !opts.json { 88 | std::io::stdout().write_all(content.paste.as_bytes())?; 89 | } else { 90 | let mut output: Value = serde_json::to_value(content)?; 91 | if !comments.is_empty() { 92 | let comments_trees = 93 | paste.comments_formatted_json_trees(&comments, &paste.comments_adjacency_map()?)?; 94 | output["comments"] = serde_json::from_str(&comments_trees)?; 95 | } 96 | std::io::stdout().write_all(serde_json::to_string_pretty(&output)?.as_bytes())?; 97 | } 98 | 99 | Ok(()) 100 | } 101 | 102 | fn handle_post(opts: &Opts) -> PbResult<()> { 103 | let url = opts.get_url(); 104 | let stdin = get_stdin()?; 105 | let api = API::new(url.clone(), opts.clone()); 106 | 107 | let password = &opts.password.clone().unwrap_or_default(); 108 | 109 | let mut paste = DecryptedPaste { 110 | paste: stdin, 111 | attachment: None, 112 | attachment_name: None, 113 | }; 114 | 115 | if let Some(path) = &opts.upload { 116 | if !path.is_file() { 117 | return Err(PasteError::NotAFile); 118 | } 119 | 120 | let mut handle = std::fs::File::open(path)?; 121 | let metadata = handle.metadata()?; 122 | check_filesize(metadata.len(), opts.size_limit); 123 | 124 | let mut data = Vec::new(); 125 | handle.read_to_end(&mut data)?; 126 | let b64_data = base64::encode(data); 127 | 128 | paste.attachment = Some(create_dataurl(path.as_os_str(), b64_data)); 129 | paste.attachment_name = Some( 130 | path.file_name() 131 | .ok_or(PasteError::NotAFile)? 132 | .to_string_lossy() 133 | .to_string(), 134 | ); 135 | } 136 | 137 | let res = api.post_paste(&paste, password, opts)?; 138 | 139 | if opts.json { 140 | let mut output: Value = serde_json::to_value(res.clone())?; 141 | output["pasteurl"] = Value::String(res.to_paste_url().to_string()); 142 | output["deleteurl"] = Value::String(res.to_delete_url().to_string()); 143 | std::io::stdout().write_all(serde_json::to_string_pretty(&output)?.as_bytes())?; 144 | } else { 145 | std::io::stdout().write_all(res.to_paste_url().as_str().as_bytes())?; 146 | writeln!(std::io::stdout())?; 147 | } 148 | 149 | Ok(()) 150 | } 151 | 152 | fn handle_comment(opts: &Opts) -> PbResult<()> { 153 | let url = opts.get_url(); 154 | let paste_id = url.query().unwrap(); 155 | let fragment = url.fragment().ok_or(PasteError::MissingDecryptionKey)?; 156 | // '-' character may be found at start of fragment. This should be stripped. 157 | // It is used to activate "warn before read" feature for burn on read pastes. 158 | let key = fragment.strip_prefix('-').unwrap_or(fragment); 159 | 160 | let stdin = get_stdin()?; 161 | let api = API::new(url.clone(), opts.clone()); 162 | let content = DecryptedComment { 163 | comment: stdin, 164 | nickname: opts.comment_as.clone(), 165 | }; 166 | let parent_id = &opts.comment_to.clone().unwrap_or(paste_id.into()); 167 | let password = &opts.password.clone().unwrap_or_default(); 168 | 169 | api.post_comment(&content, paste_id, parent_id, key, password, opts)?; 170 | 171 | Ok(()) 172 | } 173 | 174 | fn handle_scrape(opts: &Opts) -> PbResult<()> { 175 | let url = opts.get_url(); 176 | let api = API::new(url.clone(), opts.clone()); 177 | let expiries = api.scrape_expiries()?; 178 | std::io::stdout().write_all(format!("{:?}", expiries).as_bytes())?; 179 | writeln!(std::io::stdout())?; 180 | Ok(()) 181 | } 182 | 183 | fn main() -> PbResult<()> { 184 | crate::logger::SimpleLogger::init()?; 185 | 186 | if pbcli::config::has_debug_flag() { 187 | log::set_max_level(log::LevelFilter::Debug); 188 | } 189 | 190 | let config_args = pbcli::config::get_config_args(pbcli::config::has_skip_default_config_flag()); 191 | let mut env_args = pbcli::config::get_cli_args(); 192 | let mut merged_args: Vec = vec![]; 193 | merged_args.extend(env_args.drain(0..1)); 194 | merged_args.extend(config_args); 195 | merged_args.extend(env_args); 196 | 197 | let opts: Opts = Opts::parse_from(&merged_args); 198 | 199 | if opts.scrape_expiries { 200 | return handle_scrape(&opts); 201 | } 202 | 203 | let url_has_query = opts.get_url().query().is_some(); 204 | if url_has_query { 205 | if opts.comment { 206 | handle_comment(&opts)?; 207 | // show paste with comments after commenting 208 | if opts.json { 209 | handle_get(&opts)?; 210 | } 211 | return Ok(()); 212 | } 213 | handle_get(&opts)?; 214 | } else { 215 | handle_post(&opts)?; 216 | } 217 | 218 | Ok(()) 219 | } 220 | -------------------------------------------------------------------------------- /src/opts.rs: -------------------------------------------------------------------------------- 1 | use crate::PasteFormat; 2 | use clap::Parser; 3 | use parse_size::parse_size; 4 | use url::Url; 5 | 6 | const ABOUT: &str = "pbcli is a command line client which allows to upload and download 7 | pastes from privatebin directly from the command line. 8 | 9 | Project home page: https://github.com/Mydayyy/pbcli"; 10 | 11 | #[derive(Debug, Parser, Clone)] 12 | #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] 13 | #[clap( version = env ! ("CARGO_PKG_VERSION"), author = "Mydayyy ", about = ABOUT)] 14 | #[clap(term_width(if let Some((terminal_size::Width(w), _)) = terminal_size::terminal_size() { w as usize } else { 120 }))] 15 | #[clap(rename_all = "kebab-case")] 16 | #[command(args_override_self = true)] 17 | pub struct Opts { 18 | #[clap(required_unless_present("host"))] 19 | pub url: Option, 20 | 21 | #[cfg_attr(feature = "uniffi", uniffi(default = None))] 22 | #[clap(long)] 23 | pub host: Option, 24 | 25 | #[clap(long, short = 'f', value_enum, default_value = "plaintext")] 26 | pub format: PasteFormat, 27 | 28 | #[cfg_attr(feature = "uniffi", uniffi(default = "1week"))] 29 | #[clap(long, short = 'e', default_value = "1week")] 30 | pub expire: String, 31 | 32 | #[cfg_attr(feature = "uniffi", uniffi(default = None))] 33 | #[clap(long)] 34 | #[arg(value_parser = |x: &str| parse_size(x))] // closure: https://github.com/clap-rs/clap/issues/4939 35 | #[clap(help( 36 | "Prompt if the paste exceeds the given size. Fail in non-interactive environments." 37 | ))] 38 | pub size_limit: Option, 39 | 40 | #[cfg_attr(feature = "uniffi", uniffi(default = false))] 41 | #[clap(long, help("richer output: for delete_url, comments, etc"))] 42 | pub json: bool, 43 | #[cfg_attr(feature = "uniffi", uniffi(default = false))] 44 | #[clap(long, short = 'b', conflicts_with = "discussion")] 45 | #[clap(overrides_with = "no_burn")] 46 | #[clap(help("enable burn on read for new paste"))] 47 | pub burn: bool, 48 | #[cfg_attr(feature = "uniffi", uniffi(default = false))] 49 | #[clap(long, short = 'B')] 50 | #[clap(help("disable burn if set"))] 51 | pub no_burn: bool, 52 | #[cfg_attr(feature = "uniffi", uniffi(default = false))] 53 | #[clap(long, short = 'd')] 54 | #[clap(overrides_with = "no_discussion")] 55 | #[clap(help("enable discussion for new paste"))] 56 | pub discussion: bool, 57 | #[cfg_attr(feature = "uniffi", uniffi(default = false))] 58 | #[clap(long, short = 'D')] 59 | #[clap(help("disable burn if set"))] 60 | pub no_discussion: bool, 61 | 62 | #[cfg_attr(feature = "uniffi", uniffi(default = false))] 63 | #[clap(long, requires("url"))] 64 | #[clap(help("make new comment on existing paste"))] 65 | pub comment: bool, 66 | #[cfg_attr(feature = "uniffi", uniffi(default = None))] 67 | #[clap(long, requires("comment"), value_name = "nickname")] 68 | #[clap(help("use this nick for comment"))] 69 | pub comment_as: Option, 70 | #[cfg_attr(feature = "uniffi", uniffi(default = None))] 71 | #[clap(long, requires("comment"), value_name = "parentid")] 72 | #[clap(help("reply to this parent comment"))] 73 | pub comment_to: Option, 74 | 75 | #[cfg_attr(feature = "uniffi", uniffi(default = None))] 76 | #[clap(long, short = 'o', value_name = "FILE")] 77 | pub download: Option, 78 | #[cfg_attr(feature = "uniffi", uniffi(default = false))] 79 | #[clap(long, short = 'w')] 80 | #[clap(help("overwrite the file given with --download if it already exists"))] 81 | pub overwrite: bool, 82 | 83 | #[cfg_attr(feature = "uniffi", uniffi(default = None))] 84 | #[clap(long, short = 'u', value_name = "FILE")] 85 | pub upload: Option, 86 | 87 | #[cfg_attr(feature = "uniffi", uniffi(default = None))] 88 | #[clap(long, short = 'p')] 89 | pub password: Option, 90 | 91 | #[cfg_attr(feature = "uniffi", uniffi(default = None))] 92 | #[clap(long, requires_all(& ["oidc_client_id", "oidc_username", "oidc_password"]))] 93 | #[clap(help("oidc token endpoint from which to obtain an access token"))] 94 | pub oidc_token_url: Option, 95 | 96 | #[cfg_attr(feature = "uniffi", uniffi(default = None))] 97 | #[clap(long)] 98 | #[clap(help("client id to send to the token endpoint"))] 99 | pub oidc_client_id: Option, 100 | 101 | #[cfg_attr(feature = "uniffi", uniffi(default = None))] 102 | #[clap(long)] 103 | #[clap(help("username to send to the token endpoint"))] 104 | pub oidc_username: Option, 105 | 106 | #[cfg_attr(feature = "uniffi", uniffi(default = None))] 107 | #[clap(long)] 108 | #[clap(help("password to send to the token endpoint"))] 109 | pub oidc_password: Option, 110 | 111 | #[cfg_attr(feature = "uniffi", uniffi(default = false))] 112 | #[clap(long)] 113 | #[clap(help("print debug output to stderr"))] 114 | pub debug: bool, 115 | 116 | #[cfg_attr(feature = "uniffi", uniffi(default = false))] 117 | #[clap(long)] 118 | #[clap(help("do not look for config in default locations"))] 119 | pub no_default_config: bool, 120 | 121 | #[cfg_attr(feature = "uniffi", uniffi(default = false))] 122 | #[clap(long)] 123 | #[clap(help("attempt scraping supported expiries of given host and exit"))] 124 | pub scrape_expiries: bool, 125 | } 126 | 127 | impl Opts { 128 | pub fn get_url(&self) -> &Url { 129 | self.url 130 | .as_ref() 131 | .unwrap_or_else(|| self.host.as_ref().unwrap()) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/privatebin.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::crypto::Decryptable; 4 | use crate::error::PbResult; 5 | use rand_core::{RngCore, SeedableRng}; 6 | use serde::ser::{SerializeTuple, Serializer}; 7 | use serde::Deserialize; 8 | use serde::Serialize; 9 | use serde_json::json; 10 | use serde_with::skip_serializing_none; 11 | use url::Url; 12 | 13 | #[derive(Default, Deserialize, Debug, Serialize)] 14 | pub enum CompressionType { 15 | #[serde(rename = "none")] 16 | None, 17 | 18 | #[default] 19 | #[serde(rename = "zlib")] 20 | Zlib, 21 | } 22 | 23 | #[derive(Default, clap::ValueEnum, Deserialize, Debug, Serialize, Clone, Copy)] 24 | #[cfg_attr(feature = "uniffi", derive(uniffi::Enum))] 25 | pub enum PasteFormat { 26 | #[default] 27 | #[serde(rename = "plaintext")] 28 | Plaintext, 29 | 30 | #[serde(rename = "syntaxhighlighting")] 31 | Syntax, 32 | 33 | #[serde(rename = "markdown")] 34 | Markdown, 35 | } 36 | 37 | #[skip_serializing_none] 38 | #[derive(Default, Deserialize, Debug, Serialize)] 39 | #[cfg_attr(feature = "uniffi", derive(uniffi::Object))] 40 | pub struct Paste { 41 | pub status: Option, 42 | pub id: String, 43 | pub url: Option, 44 | pub v: i32, 45 | pub ct: String, 46 | pub meta: Meta, 47 | pub adata: Data, 48 | pub comments: Option>, 49 | } 50 | 51 | impl Decryptable for Paste { 52 | fn get_ct(&self) -> &str { 53 | &self.ct 54 | } 55 | fn get_cipher(&self) -> &Cipher { 56 | &self.adata.cipher 57 | } 58 | fn get_adata_str(&self) -> String { 59 | serde_json::to_string(&self.adata).unwrap() 60 | } 61 | } 62 | 63 | #[derive(Default, Deserialize, Debug, Serialize)] 64 | pub struct Comment { 65 | pub id: String, 66 | pub pasteid: String, 67 | pub parentid: String, 68 | pub v: i32, 69 | pub ct: String, 70 | pub meta: Meta, 71 | pub adata: Cipher, 72 | } 73 | 74 | impl Decryptable for Comment { 75 | fn get_ct(&self) -> &str { 76 | &self.ct 77 | } 78 | fn get_cipher(&self) -> &Cipher { 79 | &self.adata 80 | } 81 | fn get_adata_str(&self) -> String { 82 | serde_json::to_string(&self.adata).unwrap() 83 | } 84 | } 85 | 86 | #[skip_serializing_none] 87 | #[derive(Default, Deserialize, Debug, Serialize)] 88 | pub struct Meta { 89 | pub created: Option, 90 | pub expire: Option, 91 | pub time_to_live: Option, 92 | pub icon: Option, 93 | } 94 | 95 | #[derive(Default, Deserialize, Debug)] 96 | pub struct Data { 97 | pub cipher: Cipher, 98 | pub format: PasteFormat, 99 | pub discuss: u8, 100 | pub burn: u8, 101 | } 102 | 103 | #[derive(Deserialize, Debug)] 104 | pub struct Cipher { 105 | pub cipher_iv: String, 106 | pub kdf_salt: String, 107 | pub kdf_iterations: u32, 108 | pub kdf_keysize: u32, 109 | pub cipher_tag_size: u32, 110 | pub cipher_algo: String, 111 | pub cipher_mode: String, 112 | pub compression_type: CompressionType, 113 | // test: String, 114 | } 115 | 116 | impl Default for Cipher { 117 | fn default() -> Self { 118 | let mut rng = rand_chacha::ChaCha20Rng::from_entropy(); 119 | let mut kdf_salt = [0u8; 8]; 120 | let mut nonce = [0u8; 16]; 121 | rng.fill_bytes(&mut kdf_salt); 122 | rng.fill_bytes(&mut nonce); 123 | 124 | Cipher { 125 | cipher_iv: base64::encode(nonce), 126 | kdf_salt: base64::encode(kdf_salt), 127 | kdf_iterations: 100000, 128 | kdf_keysize: 256, 129 | cipher_tag_size: 128, 130 | cipher_algo: "aes".to_string(), 131 | cipher_mode: "gcm".to_string(), 132 | compression_type: CompressionType::Zlib, 133 | } 134 | } 135 | } 136 | 137 | impl Cipher { 138 | /// get vector of bytes representation 139 | pub fn vec_cipher_iv(&self) -> PbResult> { 140 | base64::decode(&self.cipher_iv).map_err(|e| e.into()) 141 | } 142 | /// get vector of bytes representation 143 | pub fn vec_kdf_salt(&self) -> PbResult> { 144 | base64::decode(&self.kdf_salt).map_err(|e| e.into()) 145 | } 146 | } 147 | 148 | #[skip_serializing_none] 149 | #[derive(Deserialize, Debug, Serialize)] 150 | #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] 151 | pub struct DecryptedPaste { 152 | pub paste: String, 153 | pub attachment: Option, 154 | pub attachment_name: Option, 155 | } 156 | 157 | #[skip_serializing_none] 158 | #[derive(Default, Deserialize, Debug, Serialize)] 159 | #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] 160 | pub struct DecryptedComment { 161 | pub comment: String, 162 | pub nickname: Option, 163 | } 164 | 165 | /// comment.id -> decrypted_comment 166 | pub type DecryptedCommentsMap = HashMap; 167 | 168 | /// comment.id -> [children comment.id] 169 | pub type CommentsAdjacencyMap = HashMap>; 170 | 171 | #[derive(Deserialize, Debug, Serialize, Clone)] 172 | #[cfg_attr(feature = "uniffi", derive(uniffi::Object))] 173 | pub struct PostCommentResponse { 174 | pub id: String, 175 | pub status: u32, 176 | pub url: String, 177 | } 178 | 179 | #[derive(Deserialize, Debug, Serialize, Clone)] 180 | #[cfg_attr(feature = "uniffi", derive(uniffi::Object))] 181 | pub struct PostPasteResponse { 182 | pub deletetoken: String, 183 | pub id: String, 184 | pub status: u32, 185 | pub url: String, 186 | pub baseurl: Url, 187 | pub bs58key: String, 188 | } 189 | 190 | #[cfg_attr(feature = "uniffi", uniffi::export)] 191 | impl PostPasteResponse { 192 | /// Return full paste url, i.e (base + ?id + #bs58key) 193 | pub fn to_paste_url(&self) -> url::Url { 194 | let mut paste_url: url::Url = self.baseurl.clone(); 195 | paste_url.set_query(Some(&self.id)); 196 | paste_url.set_fragment(Some(&self.bs58key)); 197 | paste_url 198 | } 199 | /// Return url that can be used to delete paste 200 | pub fn to_delete_url(&self) -> url::Url { 201 | let mut delete_url: url::Url = self.baseurl.clone(); 202 | delete_url 203 | .query_pairs_mut() 204 | .append_pair("pasteid", &self.id) 205 | .append_pair("deletetoken", &self.deletetoken); 206 | delete_url 207 | } 208 | pub fn to_json_string(&self) -> String { 209 | serde_json::to_string(&self).unwrap() 210 | } 211 | pub fn is_success(&self) -> bool { 212 | self.status == 0 213 | } 214 | } 215 | 216 | #[cfg_attr(feature = "uniffi", uniffi::export)] 217 | impl Paste { 218 | pub fn decrypt(&self, bs58_key: &str) -> PbResult { 219 | self.decrypt_with_password(bs58_key, "") 220 | } 221 | 222 | pub fn decrypt_with_password( 223 | &self, 224 | bs58_key: &str, 225 | password: &str, 226 | ) -> PbResult { 227 | let key = bs58::decode(bs58_key).into_vec()?; 228 | crate::crypto::decrypt_with_password(self, &key, password) 229 | } 230 | 231 | /// Returns a mapping: comment.id -> decrypted_comment 232 | pub fn decrypt_comments(&self, bs58_key: &str) -> PbResult { 233 | self.decrypt_comments_with_password(bs58_key, "") 234 | } 235 | 236 | /// Returns a mapping: comment.id -> decrypted_comment 237 | pub fn decrypt_comments_with_password( 238 | &self, 239 | bs58_key: &str, 240 | password: &str, 241 | ) -> PbResult { 242 | let mut decrypted_comments = HashMap::new(); 243 | if let Some(comments) = &self.comments { 244 | for comment in comments { 245 | let id = comment.id.clone(); 246 | decrypted_comments.insert(id, comment.decrypt_with_password(bs58_key, password)?); 247 | } 248 | }; 249 | Ok(decrypted_comments) 250 | } 251 | 252 | /// Returns a mapping: comment.id -> [children comment.id] 253 | pub fn comments_adjacency_map(&self) -> PbResult { 254 | let mut comment_adjacency: CommentsAdjacencyMap = HashMap::new(); 255 | if let Some(comments) = &self.comments { 256 | for c in comments { 257 | let id = c.id.clone(); 258 | let parentid = c.parentid.clone(); 259 | comment_adjacency.entry(parentid).or_default().push(id); 260 | } 261 | } 262 | Ok(comment_adjacency) 263 | } 264 | 265 | /// Returns formatted json trees (forest) of decrypted comments 266 | pub fn comments_formatted_json_trees( 267 | &self, 268 | decrypted_comments: &DecryptedCommentsMap, 269 | comment_adjacency: &CommentsAdjacencyMap, 270 | ) -> PbResult { 271 | fn format_comments_below_id( 272 | id: &str, 273 | decrypted_comments: &DecryptedCommentsMap, 274 | comment_adjacency: &CommentsAdjacencyMap, 275 | ) -> serde_json::Value { 276 | let formatted_children: Vec = comment_adjacency 277 | .get(id) 278 | .unwrap_or(&Vec::new()) 279 | .iter() 280 | .map(|child_id| { 281 | format_comments_below_id(child_id, decrypted_comments, comment_adjacency) 282 | }) 283 | .collect(); 284 | json!({ 285 | "id": id, 286 | "comment": decrypted_comments.get(id).unwrap_or(&DecryptedComment::default()).comment, 287 | "nickname": decrypted_comments.get(id).unwrap_or(&DecryptedComment::default()).nickname, 288 | "replies": formatted_children 289 | }) 290 | } 291 | let top_level = format_comments_below_id(&self.id, decrypted_comments, comment_adjacency); 292 | serde_json::to_string_pretty(&top_level["replies"]).map_err(|e| e.into()) 293 | } 294 | } 295 | 296 | impl Comment { 297 | pub fn decrypt(&self, bs58_key: &str) -> PbResult { 298 | self.decrypt_with_password(bs58_key, "") 299 | } 300 | 301 | pub fn decrypt_with_password( 302 | &self, 303 | bs58_key: &str, 304 | password: &str, 305 | ) -> PbResult { 306 | let key = bs58::decode(bs58_key).into_vec()?; 307 | crate::crypto::decrypt_with_password(self, &key, password) 308 | } 309 | } 310 | 311 | /// Data struct needs to be serialized as an ordered array (not object), 312 | /// so we implement custom serialization. 313 | impl Serialize for Data { 314 | fn serialize(&self, serializer: S) -> Result 315 | where 316 | S: Serializer, 317 | { 318 | let mut s = serializer.serialize_tuple(4)?; 319 | s.serialize_element(&self.cipher)?; 320 | s.serialize_element(&self.format)?; 321 | s.serialize_element(&self.discuss)?; 322 | s.serialize_element(&self.burn)?; 323 | s.end() 324 | } 325 | } 326 | 327 | /// Cipher struct needs to be serialized as an ordered array (not object), 328 | /// so we implement custom serialization. 329 | impl Serialize for Cipher { 330 | fn serialize(&self, serializer: S) -> Result 331 | where 332 | S: Serializer, 333 | { 334 | let mut s = serializer.serialize_tuple(8)?; 335 | s.serialize_element(&self.cipher_iv)?; 336 | s.serialize_element(&self.kdf_salt)?; 337 | s.serialize_element(&self.kdf_iterations)?; 338 | s.serialize_element(&self.kdf_keysize)?; 339 | s.serialize_element(&self.cipher_tag_size)?; 340 | s.serialize_element(&self.cipher_algo)?; 341 | s.serialize_element(&self.cipher_mode)?; 342 | s.serialize_element(&self.compression_type)?; 343 | s.end() 344 | } 345 | } 346 | -------------------------------------------------------------------------------- /src/uniffi_custom_types.rs: -------------------------------------------------------------------------------- 1 | use reqwest::Url; 2 | use std::path::PathBuf; 3 | 4 | use crate::UniffiCustomTypeConverter; 5 | // Custom UniFFI types 6 | 7 | // `Url` as a custom type, with `String` as the Builtin 8 | uniffi::custom_type!(Url, String); 9 | 10 | impl UniffiCustomTypeConverter for Url { 11 | type Builtin = String; 12 | 13 | fn into_custom(val: Self::Builtin) -> uniffi::Result { 14 | val.parse::().map_err(|e| e.into()) 15 | } 16 | 17 | fn from_custom(obj: Self) -> Self::Builtin { 18 | obj.as_str().to_owned() 19 | } 20 | } 21 | 22 | // `PathBuf` as a custom type, with `String` as the Builtin 23 | uniffi::custom_type!(PathBuf, String); 24 | 25 | impl UniffiCustomTypeConverter for PathBuf { 26 | type Builtin = String; 27 | 28 | fn into_custom(val: Self::Builtin) -> uniffi::Result { 29 | Ok(PathBuf::from(val)) 30 | } 31 | 32 | fn from_custom(obj: Self) -> Self::Builtin { 33 | format!("{:?}", obj.display()) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | use std::io::IsTerminal; 2 | use std::process::exit; 3 | use std::sync::Mutex; 4 | 5 | pub fn check_filesize(len: u64, opts_size_limt: Option) { 6 | static MUTEX_IS_CONFIRMED: Mutex = Mutex::new(false); 7 | let mut user_confirmed_size = MUTEX_IS_CONFIRMED.lock().unwrap(); 8 | 9 | if *user_confirmed_size { 10 | return; 11 | } 12 | 13 | if let Some(size_limit) = opts_size_limt { 14 | if len > size_limit { 15 | if !std::io::stdin().is_terminal() { 16 | exit(1) 17 | } 18 | 19 | let confirmation = dialoguer::Confirm::new() 20 | .with_prompt("This paste exceeds your defined size limit. Continue?") 21 | .interact() 22 | .unwrap(); 23 | 24 | if !confirmation { 25 | exit(1) 26 | } 27 | *user_confirmed_size = true; 28 | } 29 | } 30 | } 31 | --------------------------------------------------------------------------------