Repository: cargo-prebuilt/cargo-prebuilt (language: rust)

Issue:
Build with native tls on github actions



Discussion / hints:

Fix patch:
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..d8ef330
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,5 @@
+* text=auto
+
+# Because of it being signed.
+test/pubdata.test text eol=lf
+test/pubdata.test.sig binary
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index da3aae8..7322402 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,6 +13,7 @@ on:
 
 env:
   bin-name: cargo-prebuilt
+  feature-set: '--no-default-features --features default-native'
   CARGO_TERM_COLOR: always
   CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
 
@@ -133,32 +134,13 @@ jobs:
             can-test: true
           - target: mips64el-unknown-linux-muslabi64
             can-test: true
-          - target: i686-unknown-linux-gnu
-            can-test: false
-          - target: i686-unknown-linux-musl
-            can-test: false
-          - target: i686-unknown-freebsd
-            can-test: false
           - target: armv7-unknown-linux-gnueabihf
             can-test: true
           - target: armv7-unknown-linux-musleabihf
             can-test: true
-          - target: powerpc-unknown-linux-gnu
-            can-test: true
-          - target: mips-unknown-linux-gnu
-            can-test: true
-          - target: mips-unknown-linux-musl
-            can-test: true
-          - target: mipsel-unknown-linux-gnu
-            can-test: true
-          - target: mipsel-unknown-linux-musl
-            can-test: true
           - target: x86_64-pc-windows-gnu
             can-test: true
             ending: .exe
-          - target: i686-pc-windows-gnu
-            can-test: true
-            ending: .exe
     runs-on: ubuntu-latest
     needs: [ setup ]
     steps:
@@ -187,9 +169,15 @@ jobs:
           tools: cross
       - name: Run tests
         if: ${{ matrix.can-test }}
-        run: cross test --verbose --workspace --locked --target ${{ matrix.target }}
+        run: cross test --verbose --workspace --locked --target ${{ matrix.target }} ${{ env.feature-set }}
       - name: Build
-        run: cross build --verbose --workspace --locked --target ${{ matrix.target }}
+        run: cross build --verbose --workspace --locked --target ${{ matrix.target }} ${{ env.feature-set }}
+      - name: Run cargo-prebuilt
+        if: ${{ contains(matrix.target, 'x86_64-unknown-linux-') }}
+        run: |
+          target/${{ matrix.target }}/debug/${{ env.bin-name }} just
+          just --version
+          target/${{ matrix.target }}/debug/${{ env.bin-name }} --color just
       - name: Artifact
         uses: actions/upload-artifact@v3
         with:
@@ -231,17 +219,20 @@ jobs:
         run: rustc --version
       - name: Add Rust target
         run: rustup target add ${{ matrix.target }}
+      - uses: cargo-prebuilt/cargo-prebuilt-action@v1
+        with:
+          tools: cargo-auditable
       - name: Run tests
         if: ${{ matrix.can-test }}
-        run: cargo test --verbose --workspace --locked --target ${{ matrix.target }}
+        run: cargo test --verbose --workspace --locked --target ${{ matrix.target }} ${{ env.feature-set }}
       - name: Build
-        run: cargo build --verbose --workspace --locked --target ${{ matrix.target }}
+        run: cargo auditable build --verbose --workspace --locked --target ${{ matrix.target }} ${{ env.feature-set }}
       - name: Run cargo-prebuilt
         if: ${{ matrix.can-test }}
         run: |
           target/${{ matrix.target }}/debug/${{ env.bin-name }} just
           just --version
-          target/${{ matrix.target }}/debug/${{ env.bin-name }} --colors just
+          target/${{ matrix.target }}/debug/${{ env.bin-name }} --color just
       - name: Artifact
         uses: actions/upload-artifact@v3
         with:
@@ -258,8 +249,6 @@ jobs:
             can-test: true
           - target: aarch64-pc-windows-msvc
             can-test: false
-          - target: i686-pc-windows-msvc
-            can-test: true
     runs-on: windows-latest
     needs: [ setup ]
     steps:
@@ -292,11 +281,14 @@ jobs:
         run: rustc --version
       - name: Add Rust target
         run: rustup target add ${{ matrix.target }}
+      - uses: cargo-prebuilt/cargo-prebuilt-action@v1
+        with:
+          tools: cargo-auditable
       - name: Run tests
         if: ${{ matrix.can-test }}
-        run: cargo test --verbose --workspace --locked --target ${{ matrix.target }}
+        run: cargo test --verbose --workspace --locked --target ${{ matrix.target }} ${{ env.feature-set }}
       - name: Build
-        run: cargo build --verbose --workspace --locked --target ${{ matrix.target }}
+        run: cargo auditable build --verbose --workspace --locked --target ${{ matrix.target }} ${{ env.feature-set }}
       - name: Run cargo-prebuilt
         if: ${{ matrix.can-test }}
         run: |
diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml
index 355174e..2bd0a29 100644
--- a/.github/workflows/checks.yml
+++ b/.github/workflows/checks.yml
@@ -12,6 +12,8 @@ on:
   workflow_dispatch:
 
 env:
+  feature-set: '--no-default-features --features native,bright-color,indexes,security'
+  hack-group: '--group-features rustls,rustls-native-certs,native,vendored-openssl --group-features bright-color,dull-color'
   CARGO_TERM_COLOR: never
   CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
 
@@ -68,7 +70,7 @@ jobs:
         run: |
           set -o pipefail
           cargo clippy --all-targets --verbose --workspace --locked -- -D warnings 2>&1 | tee .step-data.txt
-          cargo clippy --all-targets --verbose --workspace --locked --no-default-features --features indexes,rustls,dull-color -- -D warnings 2>&1 | tee .step-data.txt
+          cargo clippy --all-targets --verbose --workspace --locked ${{ env.feature-set }} -- -D warnings 2>&1 | tee .step-data.txt
       - name: Put into summary (success)
         if: success()
         shell: bash
@@ -110,12 +112,17 @@ jobs:
         run: rustc --version
       - uses: cargo-prebuilt/cargo-prebuilt-action@v1
         with:
-          tools: just
-      - name: Check features
+          tools: cargo-hack
+      - name: Hack Check (each-feature)
         shell: bash
         run: |
           set -o pipefail
-          just check-features 2>&1 | tee .step-data.txt
+          cargo hack check --each-feature --no-dev-deps --verbose --workspace --locked 2>&1 | tee .step-data.txt
+      - name: Hack Check (feature-powerset)
+        shell: bash
+        run: |
+          set -o pipefail
+          cargo hack check --feature-powerset ${{ env.hack-group }} --no-dev-deps --verbose --workspace --locked 2>&1 | tee .step-data.txt
       - name: Put into summary (success)
         if: success()
         shell: bash
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f7d8155..6f9cefc 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -12,7 +12,8 @@ on:
 
 env:
   bin-name: cargo-prebuilt
-  allow-cross-auditable: true
+  feature-set: '--no-default-features --features default-native'
+  hack-group: '--group-features rustls,rustls-native-certs,native,vendored-openssl --group-features bright-color,dull-color'
   CARGO_TERM_COLOR: always
   CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
 
@@ -134,7 +135,7 @@ jobs:
         run: |
           set -o pipefail
           cargo clippy --all-targets --verbose --workspace --release --locked -- -D warnings 2>&1 | tee .step-data.txt
-          cargo clippy --all-targets --verbose --workspace --release --locked --no-default-features --features indexes,rustls,dull-color -- -D warnings 2>&1 | tee .step-data.txt
+          cargo clippy --all-targets --verbose --workspace --release --locked ${{ env.feature-set }} -- -D warnings 2>&1 | tee .step-data.txt
       - name: Put into summary (success)
         if: success()
         shell: bash
@@ -185,12 +186,17 @@ jobs:
         run: rustc --version
       - uses: cargo-prebuilt/cargo-prebuilt-action@v1
         with:
-          tools: just
-      - name: Check features
+          tools: cargo-hack
+      - name: Hack Check (each-feature)
         shell: bash
         run: |
           set -o pipefail
-          just check-features 2>&1 | tee .step-data.txt
+          cargo hack check --each-feature --no-dev-deps --verbose --workspace --release --locked 2>&1 | tee .step-data.txt
+      - name: Hack Check (feature-powerset)
+        shell: bash
+        run: |
+          set -o pipefail
+          cargo hack check --feature-powerset ${{ env.hack-group }} --no-dev-deps --verbose --workspace --release --locked 2>&1 | tee .step-data.txt
       - name: Put into summary (success)
         if: success()
         shell: bash
@@ -243,7 +249,7 @@ jobs:
         with:
           tools: cargo-binstall
       - name: Install cargo-msrv
-        run: cargo binstall --version 0.16.0-beta.11 --no-confirm cargo-msrv
+        run: cargo binstall --version 0.16.0-beta.14 --no-confirm cargo-msrv
       - name: MSRV Check
         shell: bash
         run: |
@@ -378,32 +384,13 @@ jobs:
             can-test: true
           - target: mips64el-unknown-linux-muslabi64
             can-test: true
-          - target: i686-unknown-linux-gnu
-            can-test: false
-          - target: i686-unknown-linux-musl
-            can-test: false
-          - target: i686-unknown-freebsd
-            can-test: false
           - target: armv7-unknown-linux-gnueabihf
             can-test: true
           - target: armv7-unknown-linux-musleabihf
             can-test: true
-          - target: powerpc-unknown-linux-gnu
-            can-test: true
-          - target: mips-unknown-linux-gnu
-            can-test: true
-          - target: mips-unknown-linux-musl
-            can-test: true
-          - target: mipsel-unknown-linux-gnu
-            can-test: true
-          - target: mipsel-unknown-linux-musl
-            can-test: true
           - target: x86_64-pc-windows-gnu
             can-test: true
             ending: .exe
-          - target: i686-pc-windows-gnu
-            can-test: true
-            ending: .exe
     runs-on: ubuntu-latest
     needs: [ setup, check-fmt, clippy, cargo-hack, cargo-msrv ]
     steps:
@@ -427,12 +414,14 @@ jobs:
           tools: cross,coreutils
       - name: Run tests
         if: ${{ matrix.can-test }}
-        run: cross test --verbose --workspace --release --locked --target ${{ matrix.target }}
-      - name: Cross add auditable support
-        if: ${{ env.allow-cross-auditable }}
-        run: curl -fsSL https://raw.githubusercontent.com/cargo-prebuilt/cross-images/main/cross-auditable/Cross.toml >> Cross.toml
+        run: cross test --verbose --workspace --release --locked --target ${{ matrix.target }} ${{ env.feature-set }}
       - name: Build
-        run: cross build --verbose --workspace --release --locked --target ${{ matrix.target }}
+        run: cross build --verbose --workspace --release --locked --target ${{ matrix.target }} ${{ env.feature-set }}
+      - name: Run cargo-prebuilt
+        if: ${{ contains(matrix.target, 'x86_64-unknown-linux-') }}
+        run: |
+          target/${{ matrix.target }}/release/${{ env.bin-name }} just
+          just --version
       - name: Tar
         run: tar czvf ${{ matrix.target }}.tar.gz -C ./target/${{ matrix.target }}/release ${{ env.bin-name }}${{ matrix.ending }}
       - name: Hash
@@ -479,9 +468,9 @@ jobs:
           tools: cargo-auditable,coreutils
       - name: Run tests
         if: ${{ matrix.can-test }}
-        run: cargo test --verbose --workspace --release --locked --target ${{ matrix.target }}
+        run: cargo test --verbose --workspace --release --locked --target ${{ matrix.target }} ${{ env.feature-set }}
       - name: Build
-        run: cargo auditable build --verbose --workspace --release --locked --target ${{ matrix.target }}
+        run: cargo auditable build --verbose --workspace --release --locked --target ${{ matrix.target }} ${{ env.feature-set }}
       - name: Run cargo-prebuilt
         if: ${{ matrix.can-test }}
         run: |
@@ -508,8 +497,6 @@ jobs:
             can-test: true
           - target: aarch64-pc-windows-msvc
             can-test: false
-          - target: i686-pc-windows-msvc
-            can-test: true
     runs-on: windows-latest
     needs: [ setup, check-fmt, clippy, cargo-hack, cargo-msrv ]
     steps:
@@ -542,9 +529,9 @@ jobs:
           tools: cargo-auditable,coreutils
       - name: Run tests
         if: ${{ matrix.can-test }}
-        run: cargo test --verbose --workspace --release --locked --target ${{ matrix.target }}
+        run: cargo test --verbose --workspace --release --locked --target ${{ matrix.target }} ${{ env.feature-set }}
       - name: Build
-        run: cargo auditable build --verbose --workspace --release --locked --target ${{ matrix.target }}
+        run: cargo auditable build --verbose --workspace --release --locked --target ${{ matrix.target }} ${{ env.feature-set }}
       - name: Run cargo-prebuilt
         if: ${{ matrix.can-test }}
         run: |
diff --git a/.gitignore b/.gitignore
index 83c7926..428a2cf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@
 /target
 
 .DS_Store
+*.tmp
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e911b31..86c840b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,29 @@
 
 ## Upcoming
 
-- Support for custom indexes. [Github private] (#24)
+## [0.6.0](https://github.com/cargo-prebuilt/cargo-prebuilt/releases/tag/v0.6.0) (DEV)
+
+- Changed how features work.
+- Errors now use eprintln!().
+- Changed error exit codes to be positive.
+- Removed nanoserde in favor of serde.
+- Bump ureq, sha2, bpaf.
+- Boost MSRV to Rust 1.65+ from Rust 1.63+.
+- version flag (--version) now uses bpaf's built in method.
+- .prebuilt folder is now by default put in the home directory, but can be overridden.
+- config.toml now more useful. (See [CONFIG](CONFIG.md))
+- Better config handling.
+- Added support for sha3_256, sha3_512, and sha512.
+- Allowed users to pick hash types to use.
+- GitHub release builds now use native-tls instead of vendored openssl.
+- Some 32-bit platforms were dropped from support. (#46)
+- Added minisign key verifying for info.json and hashes.json.
+- Uses abort for panics.
+- File install locations are outputted into stdout. (#45)
+- Switch to gen2 index. (#43)
+- Reports can no longer be printed to stdout.
+- Extracted binaries are now checked with a hash.
+- Permissions are now explictly set to 755 on unix platforms.
 
 ## [0.5.3](https://github.com/cargo-prebuilt/cargo-prebuilt/releases/tag/v0.5.3)
 
diff --git a/CONFIG.md b/CONFIG.md
index ac454b6..5322914 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -2,17 +2,39 @@
 
 Config info is prioritized in the order of arguments -> environmental variables -> config file -> defaults.
 
+## Args
+
+Use ```cargo prebuilt --help```.
+
 ## File
 
-The config file is under ```$HOME/.config/cargo-prebuilt/config.toml```.
+The config file should be under ```$HOME/.config/cargo-prebuilt/config.toml```.
 
 The config file is ignored when using the --ci flag.
 
 ```toml
 [prebuilt]
-index = "$INDEX"
+target = "$TARGET"          # Target to download for
+index = "$INDEX"            # Index to use
+auth = "$TOKEN"             # Index auth token
+path = "$PATH"              # Absolute path to where the binaries will be installed
+report_path = "$PATH"       # Absolute path to where the reports will be put
+no_create_path = true|false # Do not create paths that do not exist
+reports = ["$REPORT_TYPE"]  # Reports to download
+hashes = ["$HASH_TYPE"]     # Hashes to use for verifying files downloaded
+color = true|false          # Should CLI colors be on or not
+force_verify = true|false   # Force verifying signatures and hashes (See [key.$ANYTHING])
+
+[key.$ANYTHING]             # Add a public verifying key for an index
+index = "$INDEX"            # Index to add key for
+pub_key = "$PUBLIC_GPG_KEY" # Public verifying key for index encoded as base64
 ```
 
 ## Ref
 
+- ```$TARGET``` is a rustc target string. EX: ```aarch64-apple-darwin```
 - ```$INDEX``` is a custom index string. EX: ```gh-pub:github.com/cargo-prebuilt/index```
+- ```$TOKEN``` is a auth token for the index.
+- ```$PATH``` is a absolute path. EX: ```/User/devops/.cargo/bin```
+- ```$REPORT_TYPE``` is a type of report. ```license, deps, audit```
+- ```$HASH_TYPE``` is a type of hash. ```sha256, sha512, sha3_256, sha3_512```
diff --git a/Cargo.lock b/Cargo.lock
index 41eeb2f..d58c156 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -35,16 +35,16 @@ dependencies = [
 ]
 
 [[package]]
-name = "base64"
-version = "0.13.1"
+name = "autocfg"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "base64"
-version = "0.21.0"
+version = "0.21.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
+checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
 
 [[package]]
 name = "bitflags"
@@ -63,9 +63,9 @@ dependencies = [
 
 [[package]]
 name = "bpaf"
-version = "0.7.10"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "423bafba382cc2c561f486bfcae41c6692833eaff0a631d10c37a9489ccd3783"
+checksum = "8bac242287491ba761f8943d48c2b3eca2b30485187a7a13fa6b2168c058f342"
 dependencies = [
  "owo-colors",
 ]
@@ -82,24 +82,29 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.12.1"
+version = "3.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8"
+checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
 
 [[package]]
 name = "cargo-prebuilt"
-version = "0.5.3"
+version = "0.6.0-dev"
 dependencies = [
+ "base64",
  "bpaf",
  "flate2",
  "hex",
  "home",
- "nanoserde",
+ "minisign",
  "native-tls",
  "owo-colors",
+ "serde",
+ "serde_json",
  "sha2",
+ "sha3",
  "tar",
  "thiserror",
+ "toml",
  "ureq",
 ]
 
@@ -115,6 +120,16 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
 [[package]]
 name = "core-foundation"
 version = "0.9.3"
@@ -133,9 +148,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.7"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
+checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c"
 dependencies = [
  "libc",
 ]
@@ -161,14 +176,21 @@ dependencies = [
 
 [[package]]
 name = "digest"
-version = "0.10.6"
+version = "0.10.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
 dependencies = [
  "block-buffer",
  "crypto-common",
+ "subtle",
 ]
 
+[[package]]
+name = "equivalent"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1"
+
 [[package]]
 name = "errno"
 version = "0.3.1"
@@ -238,9 +260,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
 
 [[package]]
 name = "form_urlencoded"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
+checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
 dependencies = [
  "percent-encoding",
 ]
@@ -255,6 +277,23 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "getrandom"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
+
 [[package]]
 name = "hermit-abi"
 version = "0.1.19"
@@ -276,6 +315,15 @@ version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
 [[package]]
 name = "home"
 version = "0.5.5"
@@ -287,14 +335,33 @@ dependencies = [
 
 [[package]]
 name = "idna"
-version = "0.3.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
+checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
 dependencies = [
  "unicode-bidi",
  "unicode-normalization",
 ]
 
+[[package]]
+name = "indexmap"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "instant"
 version = "0.1.12"
@@ -306,9 +373,9 @@ dependencies = [
 
 [[package]]
 name = "io-lifetimes"
-version = "1.0.10"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
 dependencies = [
  "hermit-abi 0.3.1",
  "libc",
@@ -321,15 +388,30 @@ version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb"
 
+[[package]]
+name = "itoa"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
+
 [[package]]
 name = "js-sys"
-version = "0.3.61"
+version = "0.3.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
+checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
 dependencies = [
  "wasm-bindgen",
 ]
 
+[[package]]
+name = "keccak"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940"
+dependencies = [
+ "cpufeatures",
+]
+
 [[package]]
 name = "lazy_static"
 version = "1.4.0"
@@ -338,48 +420,47 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.142"
+version = "0.2.147"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.3.6"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c"
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
 
 [[package]]
 name = "log"
-version = "0.4.17"
+version = "0.4.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
-dependencies = [
- "cfg-if",
-]
+checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
 
 [[package]]
-name = "miniz_oxide"
-version = "0.7.1"
+name = "memchr"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
-dependencies = [
- "adler",
-]
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
-name = "nanoserde"
-version = "0.1.32"
+name = "minisign"
+version = "0.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "755e7965536bc54d7c9fba2df5ada5bf835b0443fd613f0a53fa199a301839d3"
+checksum = "d2b6f58413c6cee060115673578e47271838f3c87cb9322c61a3bcd6d740b7d2"
 dependencies = [
- "nanoserde-derive",
+ "getrandom",
+ "rpassword",
+ "scrypt",
 ]
 
 [[package]]
-name = "nanoserde-derive"
-version = "0.1.19"
+name = "miniz_oxide"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed7a94da6c6181c35d043fc61c43ac96d3a5d739e7b8027f77650ba41504d6ab"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+dependencies = [
+ "adler",
+]
 
 [[package]]
 name = "native-tls"
@@ -401,15 +482,15 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.17.1"
+version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
 [[package]]
 name = "openssl"
-version = "0.10.52"
+version = "0.10.55"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56"
+checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d"
 dependencies = [
  "bitflags",
  "cfg-if",
@@ -428,7 +509,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.15",
+ "syn",
 ]
 
 [[package]]
@@ -439,18 +520,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
 [[package]]
 name = "openssl-src"
-version = "111.25.0+1.1.1t"
+version = "111.26.0+1.1.1u"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3173cd3626c43e3854b1b727422a276e568d9ec5fe8cec197822cf52cfb743d6"
+checksum = "efc62c9f12b22b8f5208c23a7200a442b2e5999f8bdf80233852122b5a4f6f37"
 dependencies = [
  "cc",
 ]
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.87"
+version = "0.9.90"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e"
+checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6"
 dependencies = [
  "cc",
  "libc",
@@ -468,32 +549,42 @@ dependencies = [
  "supports-color",
 ]
 
+[[package]]
+name = "pbkdf2"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31"
+dependencies = [
+ "digest",
+ "hmac",
+]
+
 [[package]]
 name = "percent-encoding"
-version = "2.2.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
+checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
 
 [[package]]
 name = "pkg-config"
-version = "0.3.26"
+version = "0.3.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
+checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.56"
+version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
+checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.26"
+version = "1.0.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
+checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
 dependencies = [
  "proc-macro2",
 ]
@@ -531,11 +622,32 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "rpassword"
+version = "7.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322"
+dependencies = [
+ "libc",
+ "rtoolbox",
+ "winapi",
+]
+
+[[package]]
+name = "rtoolbox"
+version = "0.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
 [[package]]
 name = "rustix"
-version = "0.37.17"
+version = "0.37.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc809f704c03a812ac71f22456c857be34185cac691a4316f27ab0f633bb9009"
+checksum = "62f25693a73057a1b4cb56179dd3c7ea21a7c6c5ee7d85781f5749b46f34b79c"
 dependencies = [
  "bitflags",
  "errno",
@@ -547,21 +659,21 @@ dependencies = [
 
 [[package]]
 name = "rustls"
-version = "0.20.8"
+version = "0.21.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
+checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f"
 dependencies = [
  "log",
  "ring",
+ "rustls-webpki",
  "sct",
- "webpki",
 ]
 
 [[package]]
 name = "rustls-native-certs"
-version = "0.6.2"
+version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50"
+checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
 dependencies = [
  "openssl-probe",
  "rustls-pemfile",
@@ -571,11 +683,36 @@ dependencies = [
 
 [[package]]
 name = "rustls-pemfile"
-version = "1.0.2"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
+dependencies = [
+ "base64",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.100.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
+
+[[package]]
+name = "salsa20"
+version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
+checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
 dependencies = [
- "base64 0.21.0",
+ "cipher",
 ]
 
 [[package]]
@@ -587,6 +724,17 @@ dependencies = [
  "windows-sys 0.42.0",
 ]
 
+[[package]]
+name = "scrypt"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f"
+dependencies = [
+ "pbkdf2",
+ "salsa20",
+ "sha2",
+]
+
 [[package]]
 name = "sct"
 version = "0.7.0"
@@ -599,9 +747,9 @@ dependencies = [
 
 [[package]]
 name = "security-framework"
-version = "2.8.2"
+version = "2.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
+checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
 dependencies = [
  "bitflags",
  "core-foundation",
@@ -612,31 +760,87 @@ dependencies = [
 
 [[package]]
 name = "security-framework-sys"
-version = "2.8.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
+checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
 dependencies = [
  "core-foundation-sys",
  "libc",
 ]
 
+[[package]]
+name = "serde"
+version = "1.0.164"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.164"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.99"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "sha2"
-version = "0.10.6"
+version = "0.10.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
+checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
 dependencies = [
  "cfg-if",
  "cpufeatures",
  "digest",
 ]
 
+[[package]]
+name = "sha3"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
+dependencies = [
+ "digest",
+ "keccak",
+]
+
 [[package]]
 name = "spin"
 version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
 
+[[package]]
+name = "subtle"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
+
 [[package]]
 name = "supports-color"
 version = "1.3.1"
@@ -649,20 +853,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.109"
+version = "2.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
+checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -682,15 +875,16 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.5.0"
+version = "3.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
+checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6"
 dependencies = [
+ "autocfg",
  "cfg-if",
  "fastrand",
  "redox_syscall 0.3.5",
  "rustix",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -710,7 +904,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.15",
+ "syn",
 ]
 
 [[package]]
@@ -728,6 +922,40 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
+[[package]]
+name = "toml"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.19.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
 [[package]]
 name = "typenum"
 version = "1.16.0"
@@ -742,9 +970,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.8"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
+checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
 
 [[package]]
 name = "unicode-normalization"
@@ -763,11 +991,11 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
 
 [[package]]
 name = "ureq"
-version = "2.6.2"
+version = "2.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d"
+checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9"
 dependencies = [
- "base64 0.13.1",
+ "base64",
  "brotli-decompressor",
  "flate2",
  "log",
@@ -775,16 +1003,16 @@ dependencies = [
  "once_cell",
  "rustls",
  "rustls-native-certs",
+ "rustls-webpki",
  "url",
- "webpki",
  "webpki-roots",
 ]
 
 [[package]]
 name = "url"
-version = "2.3.1"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
+checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
 dependencies = [
  "form_urlencoded",
  "idna",
@@ -803,11 +1031,17 @@ version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.84"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
+checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -815,24 +1049,24 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.84"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
+checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
 dependencies = [
  "bumpalo",
  "log",
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.84"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
+checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -840,50 +1074,40 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.84"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
+checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.84"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
+checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
 
 [[package]]
 name = "web-sys"
-version = "0.3.61"
+version = "0.3.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
 ]
 
-[[package]]
-name = "webpki"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
-dependencies = [
- "ring",
- "untrusted",
-]
-
 [[package]]
 name = "webpki-roots"
-version = "0.22.6"
+version = "0.23.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
+checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338"
 dependencies = [
- "webpki",
+ "rustls-webpki",
 ]
 
 [[package]]
@@ -923,44 +1147,20 @@ dependencies = [
  "windows_x86_64_msvc 0.42.2",
 ]
 
-[[package]]
-name = "windows-sys"
-version = "0.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
-dependencies = [
- "windows-targets 0.42.2",
-]
-
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
- "windows-targets 0.48.0",
+ "windows-targets",
 ]
 
 [[package]]
 name = "windows-targets"
-version = "0.42.2"
+version = "0.48.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
+checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
 dependencies = [
  "windows_aarch64_gnullvm 0.48.0",
  "windows_aarch64_msvc 0.48.0",
@@ -1055,6 +1255,15 @@ version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
 
+[[package]]
+name = "winnow"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "xattr"
 version = "0.2.3"
diff --git a/Cargo.toml b/Cargo.toml
index d472e70..b89ccd9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cargo-prebuilt"
-version = "0.5.3"
+version = "0.6.0-dev"
 edition = "2021"
 authors = ["harmless-tech"]
 description = "Download prebuilt crate binaries for many different platforms"
@@ -9,11 +9,9 @@ license = "MIT"
 #homepage = ""
 repository = "https://github.com/cargo-prebuilt/cargo-prebuilt"
 keywords = ["cargo", "cargo-subcommand", "binary"]
-rust-version = "1.63"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
+rust-version = "1.65"
 include = [
+    "keys/",
     "src/",
     "build.rs",
     "Cargo.lock",
@@ -23,20 +21,28 @@ include = [
 ]
 
 [dependencies]
-bpaf = { version = "0.7.10", features = ["autocomplete", "batteries"] }
+base64 = { version = "0.21.2", optional = true }
+bpaf = { version = "0.8.1", features = ["autocomplete", "batteries"] }
 flate2 = "1.0.26"
 hex = "0.4.3"
 home = "0.5.5"
-nanoserde = "0.1.32"
+minisign = { version = "0.7.5", optional = true }
 native-tls = { version = "0.2.11", optional = true }
 owo-colors = { version = "3.5.0", features = ["supports-colors"] }
-sha2 = "0.10.6"
+serde = { version = "1.0.164", features = ["derive"] }
+serde_json = "1.0.99"
+sha2 = { version = "0.10.7", optional = true }
+sha3 = { version = "0.10.8", optional = true }
 tar = "0.4.38"
 thiserror = "1.0.40"
-ureq = { version = "2.6.2", default-features = false, features = ["gzip", "brotli"] }
+toml = { version = "0.7.5", default-features = false, features = ["parse"] }
+ureq = { version = "2.7.1", default-features = false, features = ["gzip", "brotli"] }
 
 [features]
-default = ["native", "vendored-openssl", "bright-color", "indexes"]
+default = ["native", "vendored-openssl", "default-no-tls"]
+default-native = ["native", "default-no-tls"]
+default-rustls = ["rustls", "default-no-tls"]
+default-no-tls = ["bright-color", "indexes", "security"]
 indexes = ["github-public"]
 github-public = []
 github-private = [] # TODO: Under dev
@@ -46,6 +52,12 @@ github-private = [] # TODO: Under dev
 #forgejo-private = [] #TODO: Under dev
 #gitea-public = ["forgejo-public"] #TODO: Under dev
 #gitea-private = ["forgejo-private"] #TODO: Under dev
+#custom-http-public = [] #TODO: Under dev
+#custom-http-private = [] #TODO: Under dev
+security = ["sha2", "sha3", "sig"]
+sha2 = ["dep:sha2"]
+sha3 = ["dep:sha3"]
+sig = ["dep:minisign", "dep:base64"]
 rustls = ["ureq/tls"]
 rustls-native-certs = ["rustls", "ureq/native-certs"]
 native = ["native-tls", "ureq/native-tls"]
@@ -58,12 +70,14 @@ opt-level = "z"
 lto = true
 codegen-units = 1
 strip = true
+panic = "abort"
 
 [profile.quick-build]
 inherits = "release"
 opt-level = 0
 lto = false
 codegen-units = 16
+panic = "abort"
 
 [package.metadata.binstall]
 pkg-url = "{ repo }/releases/download/v{ version }/{ target }.tar.gz"
@@ -79,8 +93,3 @@ pkg-fmt = "zip"
 pkg-url = "{ repo }/releases/download/v{ version }/{ target }.zip"
 bin-dir = "{ bin }{ binary-ext }"
 pkg-fmt = "zip"
-
-[package.metadata.binstall.overrides.i686-pc-windows-msvc]
-pkg-url = "{ repo }/releases/download/v{ version }/{ target }.zip"
-bin-dir = "{ bin }{ binary-ext }"
-pkg-fmt = "zip"
diff --git a/Cross.toml b/Cross.toml
new file mode 100644
index 0000000..1cf0b99
--- /dev/null
+++ b/Cross.toml
@@ -0,0 +1,59 @@
+[target.x86_64-unknown-linux-gnu]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:x86_64-unknown-linux-gnu"
+
+[target.x86_64-unknown-linux-musl]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:x86_64-unknown-linux-musl"
+
+[target.aarch64-unknown-linux-gnu]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:aarch64-unknown-linux-gnu"
+
+[target.aarch64-unknown-linux-musl]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:aarch64-unknown-linux-musl"
+
+[target.x86_64-unknown-freebsd]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:x86_64-unknown-freebsd"
+
+[target.x86_64-unknown-netbsd]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:x86_64-unknown-netbsd"
+
+[target.x86_64-unknown-illumos]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:x86_64-unknown-illumos"
+
+[target.x86_64-sun-solaris]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:x86_64-sun-solaris"
+
+[target.riscv64gc-unknown-linux-gnu]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:riscv64gc-unknown-linux-gnu"
+
+[target.powerpc64-unknown-linux-gnu]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:powerpc64-unknown-linux-gnu"
+
+[target.powerpc64le-unknown-linux-gnu]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:powerpc64le-unknown-linux-gnu"
+
+[target.s390x-unknown-linux-gnu]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:s390x-unknown-linux-gnu"
+
+[target.mips64-unknown-linux-gnuabi64]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:mips64-unknown-linux-gnuabi64"
+
+[target.mips64-unknown-linux-muslabi64]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:mips64-unknown-linux-muslabi64"
+
+[target.mips64el-unknown-linux-gnuabi64]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:mips64el-unknown-linux-gnuabi64"
+
+[target.mips64el-unknown-linux-muslabi64]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:mips64el-unknown-linux-muslabi64"
+
+[target.armv7-unknown-linux-gnueabihf]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:armv7-unknown-linux-gnueabihf"
+
+[target.armv7-unknown-linux-musleabihf]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:armv7-unknown-linux-musleabihf"
+
+[target.x86_64-pc-windows-gnu]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:x86_64-pc-windows-gnu"
+
+[target.i686-pc-windows-gnu]
+image = "ghcr.io/cargo-prebuilt/cross-openssl:i686-pc-windows-gnu"
diff --git a/README.md b/README.md
index 4d05c94..f9ea438 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
 [![Rust Build and Test](https://github.com/cargo-prebuilt/cargo-prebuilt/actions/workflows/build.yml/badge.svg?event=push)](https://github.com/cargo-prebuilt/cargo-prebuilt/actions/workflows/build.yml)
 [![Rust Checks](https://github.com/cargo-prebuilt/cargo-prebuilt/actions/workflows/checks.yml/badge.svg?event=push)](https://github.com/cargo-prebuilt/cargo-prebuilt/actions/workflows/checks.yml)
 [![Crates.io](https://img.shields.io/crates/v/cargo-prebuilt)](https://crates.io/crates/cargo-prebuilt)
-[![rustc-msrv](https://img.shields.io/badge/rustc-1.63%2B-blue?logo=rust)](https://www.rust-lang.org/tools/install)
+[![rustc-msrv](https://img.shields.io/badge/rustc-1.65%2B-blue?logo=rust)](https://www.rust-lang.org/tools/install)
 
 Download prebuilt binaries of some crate.io crates.
 
@@ -36,16 +36,20 @@ Need help? Try: ```cargo prebuilt --help``` or see [Config Info](CONFIG.md)
 ## Building
 
 #### vendored-openssl (default)
-```cargo install cargo-prebuilt --no-default-features --features indexes,vendored-openssl```
+```cargo install cargo-prebuilt --no-default-features --features indexes,security,bright-color,vendored-openssl```
 
-#### native tls
-```cargo install cargo-prebuilt --no-default-features --features indexes,native```
+#### native tls (github actions/releases default)
+```cargo install cargo-prebuilt --no-default-features --features indexes,security,bright-color,native```
 
 #### rustls
-```cargo install cargo-prebuilt --no-default-features --features indexes,rustls```
+```cargo install cargo-prebuilt --no-default-features --features indexes,security,bright-color,rustls```
 
 #### rustls with native certs
-```cargo install cargo-prebuilt --no-default-features --features indexes,rustls-native-certs```
+```cargo install cargo-prebuilt --no-default-features --features indexes,security,bright-color,rustls-native-certs```
+
+### limit security used
+Remove ```security``` feature included by default, then add the features you want below:
+- 
 
 #### limit indexes used
 Remove ```indexes``` feature included by default, then add the features you want below:
@@ -57,6 +61,8 @@ Remove ```indexes``` feature included by default, then add the features you want
 - [forgejo-private](#forgejo-private) (Not supported yet)
 - [gitea-public](#gitea-public) (Not supported yet)
 - [gitea-private](#gitea-private) (Not supported yet)
+- [custom-http-public](#custom-http-private) (Not supported yet)
+- [custom-http-private](#custom-http-private) (Not supported yet)
 
 #### colors
 ```bright-color``` feature is used by default.
@@ -66,15 +72,12 @@ Add feature ```bright-color``` or ```dull-color```.
 
 Reports are generated when a crate is built in the index.
 
-They are stored under INSTALL_PATH/.prebuilt/reports/CRATE/VERSION.
+They are stored under $HOME/.prebuilt/reports/CRATE/VERSION by default.
 
 Report types (--reports):
-- license-out: Print license to stdout.
-- license-dl: Download license and put it under the prebuilt folder in the installation dir. (Default on)
-- deps-out: Print deps tree to stdout.
-- deps-dl: Download deps tree and put it under the prebuilt folder in the installation dir.
-- audit-out: Print audit to stdout.
-- audit-dl: Download audit and put it under the prebuilt folder in the installation dir.
+- license: Download license and put it under the prebuilt folder in the installation dir. (Default on)
+- deps: Download deps tree and put it under the prebuilt folder in the installation dir.
+- audit: Download audit and put it under the prebuilt folder in the installation dir.
 
 ## Using a custom index
 
@@ -84,8 +87,9 @@ Report types (--reports):
 
 Your url should be formatted like ```github.com/cargo-prebuilt/index```. cargo-prebuilt requires https.
 
-- ```export PREBUILT_INDEX=gh-pub:URL```
-- ```cargo prebuilt --index=gh-pub:URL CRATES```
+- ```export PREBUILT_INDEX=gh-pub:$URL```
+- ```cargo prebuilt --index=gh-pub:$URL CRATES```
+- [config.toml](CONFIG.md) ```index = "gh-pub:$URL"```
 
 #### GitHub private
 
diff --git a/justfile b/justfile
index 7fd3d7d..8576dff 100644
--- a/justfile
+++ b/justfile
@@ -13,7 +13,8 @@ fmt:
 check:
     cargo +nightly fmt --check
     cargo clippy --all-targets --locked --workspace -- -D warnings
-    cargo clippy --all-targets --locked --workspace --no-default-features --features indexes,rustls,dull-color -- -D warnings
+    cargo clippy --all-targets --locked --workspace --no-default-features --features default-native -- -D warnings
+    cargo clippy --all-targets --locked --workspace --no-default-features --features default-rustls -- -D warnings
 
 docker:
     docker run -it --rm --pull=always \
@@ -33,15 +34,14 @@ docker-alpine:
     rust:alpine \
     sh
 
-# Removed for now since some features are mutually exclusive
-#hack:
-#    docker run -t --rm --pull=always \
-#    -e CARGO_TARGET_DIR=/ptarget \
-#    --mount type=bind,source={{pwd}},target=/prebuilt \
-#    --mount type=bind,source=$HOME/.cargo/registry,target=/usr/local/cargo/registry \
-#    -w /prebuilt \
-#    rust:latest \
-#    bash -c 'cargo run -- cargo-hack && cargo hack check --each-feature --no-dev-deps --verbose --workspace --locked && cargo hack check --feature-powerset --no-dev-deps --verbose --workspace --locked'
+hack:
+    docker run -t --rm --pull=always \
+    -e CARGO_TARGET_DIR=/ptarget \
+    --mount type=bind,source={{pwd}},target=/prebuilt \
+    --mount type=bind,source=$HOME/.cargo/registry,target=/usr/local/cargo/registry \
+    -w /prebuilt \
+    rust:latest \
+    bash -c 'cargo run -- cargo-hack && cargo hack check --each-feature --no-dev-deps --verbose --workspace --locked && cargo hack check --feature-powerset --group-features rustls,rustls-native-certs,native,vendored-openssl --group-features bright-color,dull-color --no-dev-deps --verbose --workspace --locked'
 
 msrv:
     docker run -t --rm --pull=always \
@@ -50,14 +50,7 @@ msrv:
     --mount type=bind,source=$HOME/.cargo/registry,target=/usr/local/cargo/registry \
     -w /prebuilt \
     rust:latest \
-    bash -c 'cargo install cargo-msrv --version 0.16.0-beta.11 --profile=dev && cargo msrv -- cargo check --verbose --locked'
-
-check-features:
-    cargo build --verbose --workspace --locked # Default
-    cargo build --verbose --workspace --locked --no-default-features --features indexes,native # All, native
-    cargo build --verbose --workspace --locked --no-default-features --features indexes,vendored-openssl # All, vendored-openssl
-    cargo build --verbose --workspace --locked --no-default-features --features indexes,rustls # All, rustls
-    cargo build --verbose --workspace --locked --no-default-features --features indexes,rustls-native-certs # All, rustls native certs
+    bash -c 'cargo install cargo-msrv --version 0.16.0-beta.14 --profile=dev && cargo msrv -- cargo check --verbose --locked'
 
 rund +ARGS:
     cargo build
diff --git a/keys/cargo-prebuilt-index.pub.base64 b/keys/cargo-prebuilt-index.pub.base64
new file mode 100644
index 0000000..55bc7ce
--- /dev/null
+++ b/keys/cargo-prebuilt-index.pub.base64
@@ -0,0 +1,1 @@
+dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXkgNTFGRjU3NTQ3OUUwOTQwMgpSV1FDbE9CNVZGZi9VWHVoRys2OTdFT1NXbFN5SVBXanllaEpwZXBqZ1E3cXNMblp4R1F6RG5xQQo=
\ No newline at end of file
diff --git a/src/args.rs b/src/args.rs
deleted file mode 100644
index 861d3e5..0000000
--- a/src/args.rs
+++ /dev/null
@@ -1,96 +0,0 @@
-use crate::TARGET;
-use bpaf::*;
-use std::path::PathBuf;
-
-pub static REPORT_FLAGS: [&str; 6] = [
-    "license-out",
-    "license-dl",
-    "deps-out",
-    "deps-dl",
-    "audit-out",
-    "audit-dl",
-];
-
-#[derive(Clone, Debug)]
-pub struct Arguments {
-    pub target: String,
-    pub index: Option<String>,
-    pub auth: Option<String>,
-    pub path: Option<PathBuf>,
-    pub ci: bool,
-    pub no_create_path: bool,
-    pub reports: String,
-    pub version: bool,
-    pub colors: bool,
-    pub no_colors: bool,
-    pub pkgs: String,
-}
-
-pub fn parse_args() -> Arguments {
-    let pkgs = positional::<String>("PKGS").help("A CSV list of packages with optional @VERSION");
-
-    let target = long("target")
-        .env("PREBUILT_TARGET")
-        .help("Target of the binary to download. (Defaults to target of cargo-prebuilt)")
-        .argument::<String>("TARGET")
-        .fallback(TARGET.to_string());
-
-    let index = long("index")
-        .env("PREBUILT_INDEX")
-        .help("Index to use. (Default: github.com/cargo-prebuilt/index)")
-        .argument::<String>("INDEX")
-        .optional();
-
-    let auth = long("auth")
-        .env("PREBUILT_AUTH")
-        .help("Auth token to use for private indexes")
-        .argument::<String>("TOKEN")
-        .optional();
-
-    let path = long("path")
-        .env("PREBUILT_PATH")
-        .help("Path to the home folder where downloaded binaries will be installed")
-        .argument::<PathBuf>("PATH")
-        .optional();
-
-    let ci = long("ci")
-        .help("Do not download reports, create a .prebuilt directory, and do not check for a config file")
-        .switch();
-
-    let no_create_path = long("no-create-path")
-        .help("Do not create the home an/or bin folder if it is missing")
-        .switch();
-
-    let reports = long("reports")
-        .env("PREBUILT_REPORTS")
-        .help("A CSV list of reports types. (license-out, license-dl, deps-out, deps-dl, audit-out, audit-dl)")
-        .argument::<String>("REPORTS")
-        .fallback("license-dl".to_string());
-
-    let version = short('v')
-        .long("version")
-        .help("Prints out program version")
-        .switch();
-
-    let colors = long("colors").help("Force colors to be turned on").switch();
-
-    let no_colors = long("no-colors")
-        .help("Force colors to be turned off")
-        .switch();
-
-    let parser = construct!(Arguments {
-        target,
-        index,
-        auth,
-        path,
-        ci,
-        no_create_path,
-        reports,
-        version,
-        colors,
-        no_colors,
-        pkgs,
-    });
-
-    cargo_helper("prebuilt", parser).to_options().run()
-}
diff --git a/src/conf_file.rs b/src/conf_file.rs
deleted file mode 100644
index 6a07fb7..0000000
--- a/src/conf_file.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-use home::home_dir;
-use std::{fs::File, io::Read};
-
-pub fn get_index() -> Option<String> {
-    let mut conf = home_dir()?;
-    conf.push(".config/cargo-prebuilt/config.toml");
-
-    if conf.exists() {
-        let mut file = File::open(conf).expect("Could not open config file.");
-        let mut str = String::new();
-        file.read_to_string(&mut str)
-            .expect("Could not read config file.");
-
-        let t = nanoserde::TomlParser::parse(str.as_str()).expect("Could not parse config file.");
-        if t.contains_key("prebuilt.index") {
-            return Some(t.get("prebuilt.index")?.str().to_string());
-        }
-    }
-
-    None
-}
diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 0000000..671244b
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,363 @@
+use crate::{
+    data::{ConfigFileV1, SigKeys},
+    DEFAULT_INDEX, TARGET,
+};
+use bpaf::*;
+use home::{cargo_home, home_dir};
+use std::{collections::HashMap, fs::File, io::Read, path::PathBuf};
+
+pub static REPORT_FLAGS: [&str; 3] = ["license", "deps", "audit"];
+
+#[derive(Clone, Debug)]
+pub struct Config {
+    pub target: String,
+    pub index: String,
+    pub auth: Option<String>,
+    pub path: PathBuf,
+    pub report_path: PathBuf,
+    pub ci: bool,
+    pub no_create_path: bool,
+    pub reports: String,
+    pub hashes: Option<String>, // Use by priority if None. (sha3_512 -> sha3_256 -> sha512 -> sha256)
+    pub sigs: SigKeys,
+    pub force_verify: bool,
+    pub pkgs: String,
+}
+
+#[derive(Clone, Debug)]
+struct Arguments {
+    target: Option<String>,
+    index: Option<String>,
+    auth: Option<String>,
+    path: Option<PathBuf>,
+    report_path: Option<PathBuf>,
+    ci: bool,
+    no_create_path: bool,
+    reports: Option<String>,
+    hashes: Option<String>,
+    sig: Option<String>,
+    force_verify: bool,
+    color: bool,
+    no_color: bool,
+    pkgs: String,
+}
+
+fn parse_args() -> Arguments {
+    let pkgs = positional::<String>("PKGS").help("A CSV list of packages with optional @VERSION");
+
+    let target = long("target")
+        .env("PREBUILT_TARGET")
+        .help("Target of the binary to download. (Defaults to target of cargo-prebuilt)")
+        .argument::<String>("TARGET")
+        .optional();
+
+    let index = long("index")
+        .env("PREBUILT_INDEX")
+        .help(format!("Index to use. (Default: {DEFAULT_INDEX})"))
+        .argument::<String>("INDEX")
+        .optional();
+
+    let auth = long("auth")
+        .env("PREBUILT_AUTH")
+        .help("Auth token to use for private indexes.")
+        .argument::<String>("TOKEN")
+        .optional();
+
+    let path = long("path")
+        .env("PREBUILT_PATH")
+        .help("Path to the folder where downloaded binaries will be installed. (Default: $CARGO_HOME)")
+        .argument::<PathBuf>("PATH")
+        .optional();
+
+    let report_path = long("report-path")
+        .env("PREBUILT_REPORT_PATH")
+        .help("Path to the folder where the reports will be put. (Default: $HOME/.prebuilt)")
+        .argument::<PathBuf>("REPORT_PATH")
+        .optional();
+
+    let ci = long("ci")
+        .env("PREBUILT_CI")
+        .help("Do not download reports, create a .prebuilt directory, and check for a config file.")
+        .switch();
+
+    let no_create_path = long("no-create-path")
+        .env("PREBUILT_NO_CREATE_PATH")
+        .help("Do not create the report and/or bin folder if it is missing.")
+        .switch();
+
+    let reports = long("reports")
+        .env("PREBUILT_REPORTS")
+        .help("A CSV list of reports types. (license, deps, audit)")
+        .argument::<String>("REPORTS")
+        .optional();
+
+    let hashes = long("hashes")
+        .env("PREBUILT_HASHES")
+        .help("A CSV list of hash types. (sha256, sha512, sha3_256, sha3_512)")
+        .argument::<String>("HASHES")
+        .optional();
+
+    let sig = long("sig")
+        .env("PREBUILT_SIG")
+        .help("A public verifying key encoded as base64. Must be used with --index.")
+        .argument::<String>("SIG")
+        .optional();
+
+    let force_verify = long("force-verify")
+        .env("PREBUILT_FORCE_VERIFY")
+        .help("Force verifying signatures and hashes.")
+        .switch();
+
+    let color = long("color")
+        .env("PREBUILT_COLOR")
+        .help("Force color to be turned on.")
+        .switch();
+
+    let no_color = long("no-color")
+        .env("PREBUILT_NO_COLOR")
+        .help("Force color to be turned off.")
+        .switch();
+
+    let parser = construct!(Arguments {
+        target,
+        index,
+        auth,
+        path,
+        report_path,
+        ci,
+        no_create_path,
+        reports,
+        hashes,
+        sig,
+        force_verify,
+        color,
+        no_color,
+        pkgs,
+    });
+
+    cargo_helper("prebuilt", parser)
+        .to_options()
+        .version(env!("CARGO_PKG_VERSION"))
+        .run()
+}
+
+fn fill_from_file(args: &mut Arguments, sig_keys: &mut SigKeys) {
+    match home_dir() {
+        Some(mut conf) => {
+            conf.push(".config/cargo-prebuilt/config.toml");
+            if conf.exists() {
+                let mut file = File::open(conf).expect("Could not open config file.");
+                let mut str = String::new();
+                file.read_to_string(&mut str)
+                    .expect("Could not read config file.");
+
+                let config: Result<ConfigFileV1, toml::de::Error> = toml::from_str(&str);
+                match config {
+                    Ok(config) => {
+                        if let Some(mut keys) = config.key {
+                            for (_, v) in keys.iter_mut() {
+                                if sig_keys.contains_key(&(v.index)) {
+                                    sig_keys
+                                        .get_mut(&(v.index))
+                                        .unwrap()
+                                        .push(v.pub_key.clone());
+                                }
+                                else {
+                                    sig_keys.insert(v.index.clone(), vec![v.pub_key.clone()]);
+                                }
+                            }
+                        }
+
+                        if let Some(prebuilt) = config.prebuilt {
+                            // TODO: Way to not clone?
+                            macro_rules! file_convert {
+                                ($($x:ident), *) => {
+                                    {
+                                        $(args.$x = args.$x.clone().or(prebuilt.$x);)*
+                                    }
+                                };
+                            }
+                            macro_rules! file_convert_switch {
+                                ($($x:ident), *) => {
+                                    {
+                                        $(if !args.$x {
+                                            if let Some(opt) = prebuilt.$x {
+                                                args.$x = opt;
+                                            }
+                                        })*
+                                    }
+                                };
+                            }
+                            macro_rules! file_convert_csv {
+                                ($($x:ident), *) => {
+                                    {
+                                        $(args.$x = args.$x.clone().or_else(|| {
+                                            prebuilt.$x.map_or_else(
+                                                || None,
+                                                |val| {
+                                                    Some(
+                                                        val.iter()
+                                                            .map(|v| {
+                                                                let str: &str = v.into();
+                                                                String::from(str)
+                                                            })
+                                                            .collect::<Vec<String>>()
+                                                            .join(","),
+                                                    )
+                                                },
+                                            )
+                                        });)*
+                                    }
+                                };
+                            }
+
+                            file_convert![target, index, auth, path, report_path];
+                            file_convert_switch![no_create_path, force_verify, color];
+
+                            // TODO: Dedupe?
+                            file_convert_csv![reports, hashes];
+                        }
+                    }
+                    Err(err) => eprintln!("Failed to parse config file.\n{err}"),
+                }
+            }
+        }
+        None => eprintln!("Could not find home directory! Config file will be ignored."),
+    }
+}
+
+fn convert(args: Arguments, sigs: SigKeys) -> Config {
+    let target = match args.target {
+        Some(val) => val,
+        None => TARGET.to_owned(),
+    };
+
+    let index = match args.index {
+        Some(val) => val,
+        None => DEFAULT_INDEX.to_string(),
+    };
+
+    let auth = args.auth;
+
+    let path = match args.path {
+        Some(val) => val,
+        None => {
+            let mut cargo_home = cargo_home().expect("Could not find cargo home directory, please set CARGO_HOME or use PREBUILT_PATH or --path");
+            if !cargo_home.ends_with("bin") {
+                cargo_home.push("bin");
+            }
+            cargo_home
+        }
+    };
+
+    let report_path = match args.report_path {
+        Some(val) => val,
+        None => {
+            let mut prebuilt_home = home_dir().expect("Could not find home directory, please set HOME or use PREBUILT_REPORT_PATH or --report-path");
+            prebuilt_home.push(".prebuilt");
+            prebuilt_home
+        }
+    };
+
+    let ci = args.ci;
+
+    let no_create_path = args.no_create_path;
+
+    let reports = match args.reports {
+        Some(val) => val,
+        None => REPORT_FLAGS[0].to_owned(),
+    };
+
+    let hashes = args.hashes;
+
+    let force_sig = args.force_verify;
+
+    match (args.color, args.no_color) {
+        #[cfg(any(feature = "bright-color", feature = "dull-color"))]
+        (true, false) => owo_colors::set_override(true),
+        (_, true) => owo_colors::set_override(false),
+        _ => {}
+    }
+
+    #[cfg(not(any(feature = "bright-color", feature = "dull-color")))]
+    owo_colors::set_override(false);
+
+    let pkgs = args.pkgs;
+
+    Config {
+        target,
+        index,
+        auth,
+        path,
+        report_path,
+        ci,
+        no_create_path,
+        reports,
+        hashes,
+        sigs,
+        force_verify: force_sig,
+        pkgs,
+    }
+}
+
+pub fn get() -> Config {
+    // arguments and env vars
+    let mut args = parse_args();
+    #[cfg(debug_assertions)]
+    dbg!(&args);
+
+    // Check if sig is used with index.
+    if args.sig.is_some() && args.index.is_none() {
+        eprintln!("--sig must be used with --index.");
+        std::process::exit(502);
+    }
+
+    let mut keys: SigKeys = HashMap::with_capacity(1);
+    keys.insert(
+        DEFAULT_INDEX.to_string(),
+        vec![include_str!("../keys/cargo-prebuilt-index.pub.base64").to_string()],
+    );
+
+    // Add sig key if needed
+    if let Some(k) = &args.sig {
+        keys.insert(args.index.clone().unwrap(), vec![k.clone()]);
+    }
+
+    // config file
+    if !args.ci {
+        fill_from_file(&mut args, &mut keys);
+        #[cfg(debug_assertions)]
+        dbg!(&args);
+    }
+
+    // Check if sig could be forced.
+    #[cfg(not(all(feature = "sig", any(feature = "sha2", feature = "sha3"))))]
+    if args.force_verify {
+        eprintln!("cargo-prebuilt needs the 'security' feature in order to force verifying. Or the 'sig' feature with one of the features 'sha2' or 'sha3'");
+        std::process::exit(224);
+    }
+
+    convert(args, keys)
+}
+
+#[cfg(test)]
+mod test {
+    use std::io::Cursor;
+
+    use minisign::{PublicKeyBox, SignatureBox};
+
+    #[test]
+    fn test_minisign1() {
+        let data = include_bytes!("../test/pubdata.test");
+        let sig = include_str!("../test/pubdata.test.minisig");
+        let pubkey = include_str!("../test/pubdata.pub");
+
+        let signature_box = SignatureBox::from_string(sig).unwrap();
+
+        let pk_box = PublicKeyBox::from_string(pubkey).unwrap();
+        let pk = pk_box.into_public_key().unwrap();
+
+        let data_reader = Cursor::new(data);
+        minisign::verify(&pk, &signature_box, data_reader, true, false, false).unwrap();
+    }
+}
diff --git a/src/data/config.rs b/src/data/config.rs
new file mode 100644
index 0000000..e1dec2a
--- /dev/null
+++ b/src/data/config.rs
@@ -0,0 +1,95 @@
+use std::{collections::HashMap, path::PathBuf};
+
+use serde::Deserialize;
+
+use super::HashType;
+
+pub type SigKeys = HashMap<String, Vec<String>>;
+
+#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Hash)]
+pub enum ReportType {
+    #[serde(rename = "license")]
+    LicenseDL,
+    #[serde(rename = "deps")]
+    DepsDL,
+    #[serde(rename = "audit")]
+    AuditDL,
+}
+impl From<ReportType> for &str {
+    fn from(value: ReportType) -> Self {
+        match value {
+            ReportType::LicenseDL => "license",
+            ReportType::DepsDL => "deps",
+            ReportType::AuditDL => "audit",
+        }
+    }
+}
+impl From<&ReportType> for &str {
+    fn from(value: &ReportType) -> Self {
+        Into::<&str>::into(*value)
+    }
+}
+impl TryFrom<&str> for ReportType {
+    type Error = ();
+
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        match value {
+            "license" => Ok(ReportType::LicenseDL),
+            "deps" => Ok(ReportType::DepsDL),
+            "audit" => Ok(ReportType::AuditDL),
+            _ => Err(()),
+        }
+    }
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct ConfigFileV1 {
+    pub prebuilt: Option<ConfigFilePrebuiltV1>,
+    pub key: Option<HashMap<String, ConfigFileKeysV1>>,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct ConfigFilePrebuiltV1 {
+    pub target: Option<String>,
+    pub index: Option<String>,
+    pub auth: Option<String>, //TODO: Should auth be base64 encoded in config file?
+    pub path: Option<PathBuf>,
+    pub report_path: Option<PathBuf>,
+    pub no_create_path: Option<bool>,
+    pub reports: Option<Vec<ReportType>>,
+    pub color: Option<bool>,
+    pub hashes: Option<Vec<HashType>>,
+    pub force_verify: Option<bool>,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct ConfigFileKeysV1 {
+    pub index: String,
+    pub pub_key: String,
+}
+
+#[cfg(test)]
+mod test {
+    use super::ConfigFileV1;
+
+    #[test]
+    fn test_deser1() {
+        let toml = include_str!("../../test/config_1.toml");
+        let _: ConfigFileV1 = toml::from_str(toml).unwrap();
+    }
+
+    #[test]
+    fn test_deser2() {
+        let toml = include_str!("../../test/config_2.toml");
+        let _: ConfigFileV1 = toml::from_str(toml).unwrap();
+    }
+
+    #[test]
+    fn test_deser3() {
+        let toml = "";
+        let _: ConfigFileV1 = toml::from_str(toml).unwrap();
+    }
+}
diff --git a/src/data/hashes.rs b/src/data/hashes.rs
new file mode 100644
index 0000000..cd61652
--- /dev/null
+++ b/src/data/hashes.rs
@@ -0,0 +1,109 @@
+use std::collections::HashMap;
+
+use serde::Deserialize;
+
+pub type Hashes = HashMap<HashType, String>;
+
+#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Hash)]
+pub enum HashType {
+    #[cfg(feature = "sha2")]
+    #[serde(rename = "sha256")]
+    Sha256,
+    #[cfg(feature = "sha2")]
+    #[serde(rename = "sha512")]
+    Sha512,
+    #[cfg(feature = "sha3")]
+    #[serde(rename = "sha3_256")]
+    Sha3_256,
+    #[cfg(feature = "sha3")]
+    #[serde(rename = "sha3_512")]
+    Sha3_512,
+}
+impl From<HashType> for &str {
+    fn from(value: HashType) -> Self {
+        match value {
+            #[cfg(feature = "sha2")]
+            HashType::Sha256 => "sha256",
+            #[cfg(feature = "sha2")]
+            HashType::Sha512 => "sha512",
+            #[cfg(feature = "sha3")]
+            HashType::Sha3_256 => "sha3_256",
+            #[cfg(feature = "sha3")]
+            HashType::Sha3_512 => "sha3_512",
+        }
+    }
+}
+impl From<&HashType> for &str {
+    fn from(value: &HashType) -> Self {
+        Into::<&str>::into(*value)
+    }
+}
+impl TryFrom<&str> for HashType {
+    type Error = ();
+
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        match value {
+            #[cfg(feature = "sha2")]
+            "sha256" => Ok(HashType::Sha256),
+            #[cfg(feature = "sha2")]
+            "sha512" => Ok(HashType::Sha512),
+            #[cfg(feature = "sha3")]
+            "sha3_256" => Ok(HashType::Sha3_256),
+            #[cfg(feature = "sha3")]
+            "sha3_512" => Ok(HashType::Sha3_512),
+            _ => Err(()),
+        }
+    }
+}
+
+/// This is an intermediate format, only for use in this program.
+#[derive(Debug)]
+pub struct HashesFileImm {
+    pub hashes: HashMap<String, HashesFileBlobV1>, // File hashes
+}
+impl From<HashesFile> for HashesFileImm {
+    fn from(value: HashesFile) -> Self {
+        match value {
+            HashesFile::V1(hashes) => Self {
+                hashes: hashes.hashes,
+            },
+        }
+    }
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(tag = "hashes_version")]
+pub enum HashesFile {
+    #[serde(rename = "1")]
+    V1(HashesFileV1),
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct HashesFileV1 {
+    pub hashes: HashMap<String, HashesFileBlobV1>, // File hashes
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct HashesFileBlobV1 {
+    pub archive: Hashes,               // Archive Hashes
+    pub bins: HashMap<String, Hashes>, // Binary Hashes
+}
+
+#[cfg(test)]
+mod test {
+    use super::HashesFile;
+
+    #[test]
+    fn test_deser1() {
+        let json = include_str!("../../test/hashes_1.json");
+        let _: HashesFile = serde_json::from_str(json).unwrap();
+    }
+
+    #[test]
+    fn test_deser2() {
+        let json = include_str!("../../test/hashes_2.json");
+        let _: HashesFile = serde_json::from_str(json).unwrap();
+    }
+}
diff --git a/src/data/info.rs b/src/data/info.rs
new file mode 100644
index 0000000..7ecb607
--- /dev/null
+++ b/src/data/info.rs
@@ -0,0 +1,93 @@
+use std::collections::HashMap;
+
+use serde::Deserialize;
+
+/// This is an intermediate format, only for use in this program.
+#[derive(Debug)]
+pub struct InfoFileImm {
+    pub id: String,                    // Crate ID
+    pub version: String,               // Crate Version
+    pub license: String,               // SPDX License String
+    pub git: String,                   // Url to Git
+    pub description: String,           // Crate Description
+    pub bins: Vec<String>,             // Crate Binaries
+    pub info: HashMap<String, String>, // Metadata
+    pub archive: InfoFileArchiveV1,    // Archive Info
+    pub files: InfoFileFilesV1,        // File Names
+    pub targets: Vec<String>,          // Targets Built For
+}
+impl From<InfoFile> for InfoFileImm {
+    fn from(value: InfoFile) -> Self {
+        match value {
+            InfoFile::V1(info) => Self {
+                id: info.id,
+                version: info.version,
+                license: info.license,
+                git: info.git,
+                description: info.description,
+                bins: info.bins,
+                info: info.info,
+                archive: info.archive,
+                files: info.files,
+                targets: info.targets,
+            },
+        }
+    }
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(tag = "info_version")]
+pub enum InfoFile {
+    #[serde(rename = "1")]
+    V1(InfoFileV1),
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct InfoFileV1 {
+    pub id: String,                    // Crate ID
+    pub version: String,               // Crate Version
+    pub license: String,               // SPDX License String
+    pub git: String,                   // Url to Git
+    pub description: String,           // Crate Description
+    pub bins: Vec<String>,             // Crate Binaries
+    pub info: HashMap<String, String>, // Metadata
+    pub archive: InfoFileArchiveV1,    // Archive Info
+    pub files: InfoFileFilesV1,        // File Names
+    pub targets: Vec<String>,          // Targets Built For
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct InfoFileArchiveV1 {
+    pub compression: String, // Archive Compression Type
+    pub ext: String,         // Archive Extension
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct InfoFileFilesV1 {
+    pub hash: String,             // Hashes File
+    pub license: String,          // License File
+    pub deps: String,             // Deps File
+    pub audit: String,            // Audit File
+    pub sig_info: Option<String>, // Sig File For Info.json
+    pub sig_hash: Option<String>, // Sig File For Hashes.json
+}
+
+#[cfg(test)]
+mod test {
+    use super::InfoFile;
+
+    #[test]
+    fn test_deser1() {
+        let json = include_str!("../../test/info_1.json");
+        let _: InfoFile = serde_json::from_str(json).unwrap();
+    }
+
+    #[test]
+    fn test_deser2() {
+        let json = include_str!("../../test/info_2.json");
+        let _: InfoFile = serde_json::from_str(json).unwrap();
+    }
+}
diff --git a/src/data/mod.rs b/src/data/mod.rs
new file mode 100644
index 0000000..31b61c0
--- /dev/null
+++ b/src/data/mod.rs
@@ -0,0 +1,7 @@
+mod config;
+mod hashes;
+mod info;
+
+pub use config::*;
+pub use hashes::*;
+pub use info::*;
diff --git a/src/get.rs b/src/get.rs
index 9ba15e1..10cdbe6 100644
--- a/src/get.rs
+++ b/src/get.rs
@@ -1,191 +1,525 @@
-use crate::{
-    args::{Arguments, REPORT_FLAGS},
-    interact::{Interact, InteractError},
-};
-use owo_colors::{OwoColorize, Stream::Stdout};
 use std::{
     fs::{create_dir_all, File},
     io::Write,
-    path::Path,
 };
 
-pub fn latest_version(interact: &dyn Interact, id: &str) -> String {
-    match interact.get_latest(id) {
-        Ok(s) => s,
-        Err(InteractError::Malformed) => {
-            println!("The version string for {id} is malformed.");
-            std::process::exit(-342);
-        }
-        Err(InteractError::HttpCode(404)) => {
-            println!(
-                "Crate {id} {} in index!",
-                "not found".if_supports_color(Stdout, |text| text.bright_red())
-            );
-            std::process::exit(-3);
-        }
-        Err(InteractError::HttpCode(code)) => {
-            println!("Http error {code} for crate {id}.");
-            std::process::exit(-4);
-        }
-        Err(_) => {
-            println!("Connection error.");
-            std::process::exit(-5);
+use crate::{
+    config::{self, Config},
+    data::{HashType, Hashes, HashesFile, HashesFileImm, InfoFile, InfoFileImm},
+    interact::{self, Interact, InteractError},
+};
+use owo_colors::{OwoColorize, Stream::Stderr};
+use ureq::Agent;
+
+#[derive(Debug, Default)]
+struct Data {
+    id: Option<String>,
+    version: Option<String>,
+    info: Option<InfoFileImm>,
+    hashes: Option<HashesFileImm>,
+}
+
+pub struct Fetcher {
+    interact: Box<dyn Interact>,
+    data: Data,
+}
+impl Fetcher {
+    pub fn new(config: &Config, agent: Agent) -> Self {
+        let interact = interact::create_interact(config.index.clone(), config.auth.as_ref(), agent);
+        Self {
+            interact,
+            data: Default::default(),
         }
     }
-}
 
-pub fn hash(interact: &dyn Interact, id: &str, version: &str, target: &str) -> String {
-    match interact.get_hash(id, version, target) {
-        Ok(s) => s,
-        Err(InteractError::Malformed) => {
-            println!("The hash string for {id} is malformed.");
-            std::process::exit(-343);
-        }
-        Err(InteractError::HttpCode(404)) => {
-            println!(
-                "Crate {id}, version {version}, and target {target} was {}! (Hash)",
-                "not found".if_supports_color(Stdout, |text| text.bright_red())
-            );
-            std::process::exit(-9);
+    pub fn reset(&mut self) {
+        self.data = Default::default();
+    }
+
+    pub fn get_version(&self) -> String {
+        self.data
+            .version
+            .as_ref()
+            .expect("Failed to get version, but it should have been guaranteed.")
+            .to_string()
+    }
+
+    pub fn load(&mut self, id: &str, version: Option<&str>) {
+        self.data.id = Some(id.to_string());
+        self.data.version = match version {
+            Some(v) => Some(v.to_string()),
+            None => Some(self.fetch_latest()),
+        };
+    }
+
+    pub fn download(&mut self, config: &Config) -> Vec<u8> {
+        let id = self
+            .data
+            .id
+            .as_ref()
+            .expect("Failed to get id, but it should have been guaranteed.");
+        let version = self
+            .data
+            .version
+            .as_ref()
+            .expect("Failed to get version, but it should have been guaranteed.");
+
+        eprintln!(
+            "{} info about {id}@{version} for target {}.",
+            "Fetching".if_supports_color(Stderr, |text| text.bright_blue()),
+            &config.target
+        );
+
+        // info.json
+        let raw_info_file = &self.fetch_str("info.json");
+        let info: InfoFile = serde_json::from_str(raw_info_file)
+            .unwrap_or_else(|_| panic!("info.json is malformed for {id}@{version}"));
+        let info: InfoFileImm = info.into();
+
+        // info.json.sig and test
+        #[cfg(feature = "sig")]
+        if let Some(sig_file) = info.files.sig_info.clone() {
+            self.verify_file("info.json", config, &sig_file, raw_info_file);
         }
-        Err(InteractError::HttpCode(code)) => {
-            println!("Http error {code} for crate {id}.");
-            std::process::exit(-10);
+        else if config.force_verify {
+            eprintln!(
+                "Could not force sig for index {}. info.json is not signed for {id}@{version}.",
+                config.index
+            );
+            std::process::exit(224);
         }
-        Err(_) => {
-            println!("Connection error.");
-            std::process::exit(-11);
+
+        #[cfg(not(feature = "sig"))]
+        if config.force_verify {
+            eprintln!(
+                "Could not force sig for index {}. Feature 'sig' is disabled.",
+                config.index
+            );
         }
-    }
-}
 
-pub fn tar(interact: &dyn Interact, id: &str, version: &str, target: &str) -> Vec<u8> {
-    println!(
-        "{} {id} {version} from {}.tar.gz",
-        "Downloading".if_supports_color(Stdout, |text| text.bright_blue()),
-        interact.pre_url(id, version, target)
-    );
-
-    match interact.get_tar(id, version, target) {
-        Ok(b) => b,
-        Err(InteractError::Malformed) => {
-            println!("The tar bytes for {id} are malformed.");
-            std::process::exit(-344);
-        }
-        Err(InteractError::HttpCode(404)) => {
-            println!(
-                "Crate {id}, version {version}, and target {target} was {}! (Tar)",
-                "not found".if_supports_color(Stdout, |text| text.bright_red())
+        // check if target is supported
+        if !info.targets.contains(&config.target) {
+            eprintln!(
+                "{id}@{version} does {} target {}",
+                "not support".if_supports_color(Stderr, |text| text.bright_red()),
+                config.target
             );
-            std::process::exit(-6);
+            std::process::exit(505);
         }
-        Err(InteractError::HttpCode(code)) => {
-            println!("Http error {code} for crate {id}.");
-            std::process::exit(-7);
+
+        // check if compression is supported
+        if !info.archive.compression.eq("gz") {
+            eprintln!("{id}@{version} does not support compression gzip");
+            std::process::exit(505);
         }
-        Err(_) => {
-            println!("Connection error.");
-            std::process::exit(-8);
+
+        // hashes.json
+        let raw_hashes_file = &self.fetch_str(&info.files.hash);
+        let hashes: HashesFile = serde_json::from_str(raw_hashes_file)
+            .unwrap_or_else(|_| panic!("{} is malformed for {id}@{version}", info.files.hash));
+        let hashes: HashesFileImm = hashes.into();
+
+        // hashes.json.sig and test
+        #[cfg(feature = "sig")]
+        if let Some(sig_file) = info.files.sig_hash.clone() {
+            self.verify_file(&info.files.hash, config, &sig_file, raw_hashes_file);
+        }
+        else if config.force_verify {
+            eprintln!(
+                "Could not force sig for index {}. info.json is not signed for {id}@{version}.",
+                config.index
+            );
+            std::process::exit(224);
         }
-    }
-}
 
-pub fn reports(interact: &dyn Interact, args: &Arguments, path: &Path, id: &str, version: &str) {
-    if !args.ci {
-        println!(
-            "{} reports... ",
-            "Getting".if_supports_color(Stdout, |text| text.bright_blue())
+        // tar
+        eprintln!(
+            "{} {id}@{version} for target {}.",
+            "Downloading".if_supports_color(Stderr, |text| text.bright_blue()),
+            &config.target
         );
+        let tar_bytes = self.fetch_blob(&format!("{}.{}", config.target, info.archive.ext));
 
-        let license_out = args.reports.contains(&REPORT_FLAGS[0].to_string());
-        let license_dl = args.reports.contains(&REPORT_FLAGS[1].to_string());
-        let deps_out = args.reports.contains(&REPORT_FLAGS[2].to_string());
-        let deps_dl = args.reports.contains(&REPORT_FLAGS[3].to_string());
-        let audit_out = args.reports.contains(&REPORT_FLAGS[4].to_string());
-        let audit_dl = args.reports.contains(&REPORT_FLAGS[5].to_string());
+        // test hashes
+        self.verify_archive(config, &hashes, &tar_bytes);
 
-        let mut report_path = path.to_path_buf();
-        report_path.push(format!(".prebuilt/reports/{id}/{version}"));
-        let report_path = report_path;
+        // store info for reports later if allowed
+        self.data.info = Some(info);
+        // store hashes for binaries later
+        self.data.hashes = Some(hashes);
 
-        // license.report
-        handle_report(
-            interact,
-            id,
-            version,
-            "license",
-            &report_path,
-            license_out,
-            license_dl,
-        );
-        // deps.report
-        handle_report(
-            interact,
-            id,
-            version,
-            "deps",
-            &report_path,
-            deps_out,
-            deps_dl,
-        );
-        // audit.report
-        handle_report(
-            interact,
-            id,
-            version,
-            "audit",
-            &report_path,
-            audit_out,
-            audit_dl,
-        );
+        tar_bytes
     }
-}
 
-fn handle_report(
-    interact: &dyn Interact,
-    id: &str,
-    version: &str,
-    name: &str,
-    report_path: &Path,
-    out: bool,
-    dl: bool,
-) {
-    if out || dl {
-        let report = match interact.get_report(id, version, name) {
-            Ok(r) => r,
-            Err(InteractError::HttpCode(404)) => {
-                println!("Could not find a {name} report in the index.");
-                return;
-            }
-            Err(_) => {
-                println!("Unknown error when trying to get {name} report.");
-                return;
+    pub fn reports(&mut self, config: &Config) {
+        if config.reports.is_empty() {
+            return;
+        }
+
+        eprintln!(
+            "{} reports... ",
+            "Getting".if_supports_color(Stderr, |text| text.bright_blue())
+        );
+
+        let id = self
+            .data
+            .id
+            .as_ref()
+            .expect("Failed to get id, but it should have been guaranteed.");
+        let version = self
+            .data
+            .version
+            .as_ref()
+            .expect("Failed to get version, but it should have been guaranteed.");
+        let info = self
+            .data
+            .info
+            .as_ref()
+            .expect("Failed to get info, but it should have been guaranteed.");
+
+        let reports: Vec<&str> = config.reports.split(',').collect();
+        for report in reports {
+            if !config::REPORT_FLAGS.contains(&report) {
+                eprintln!("Bad report type: {report}.");
+                std::process::exit(600);
             }
-        };
 
-        if out {
-            println!("{name}.report:\n{report}");
-        }
+            let report_name = match report {
+                "license" => info.files.license.clone(),
+                "deps" => info.files.deps.clone(),
+                "audit" => info.files.audit.clone(),
+                _ => panic!("Bad report type, but this should never be reached."),
+            };
+
+            let raw_str = &self.fetch_str(&report_name);
 
-        if dl {
-            let mut dir = report_path.to_path_buf();
+            let mut dir = config.report_path.clone();
+            dir.push(format!("{id}/{version}"));
             match create_dir_all(&dir) {
                 Ok(_) => {
-                    dir.push(format!("{name}.report"));
+                    dir.push(&report_name);
                     match File::create(&dir) {
-                        Ok(mut file) => match file.write(report.as_bytes()) {
+                        Ok(mut file) => match file.write(raw_str.as_bytes()) {
                             Ok(_) => {}
                             Err(_) => {
-                                println!("Could not write to {name}.report file.")
+                                eprintln!("Could not write to {report_name} file.")
                             }
                         },
-                        Err(_) => println!("Could not create {name}.report file."),
+                        Err(_) => eprintln!("Could not create {report_name} file."),
                     }
                 }
                 Err(_) => {
-                    println!("Could not create directories for {name}.report.")
+                    eprintln!("Could not create directories for {report_name}.")
+                }
+            }
+        }
+    }
+
+    fn fetch_latest(&self) -> String {
+        let id = self
+            .data
+            .id
+            .as_ref()
+            .expect("Failed to get id, but it should have been guaranteed.");
+
+        match self.interact.get_latest(id.as_str()) {
+            Ok(s) => s,
+            Err(InteractError::Malformed) => {
+                eprintln!("The version string for {id} is malformed.");
+                std::process::exit(342);
+            }
+            Err(InteractError::HttpCode(404)) => {
+                eprintln!(
+                    "Crate {id} {} in index!",
+                    "not found".if_supports_color(Stderr, |text| text.bright_red())
+                );
+                std::process::exit(3);
+            }
+            Err(InteractError::HttpCode(code)) => {
+                eprintln!("Http error {code} for crate {id}.");
+                std::process::exit(4);
+            }
+            Err(err) => {
+                eprintln!("Connection error.\n{err}");
+                std::process::exit(5);
+            }
+        }
+    }
+
+    fn fetch_str(&self, file: &str) -> String {
+        let id = self
+            .data
+            .id
+            .as_ref()
+            .expect("Failed to get id, but it should have been guaranteed.");
+        let version = self
+            .data
+            .version
+            .as_ref()
+            .expect("Failed to get version, but it should have been guaranteed.");
+
+        match self.interact.get_str(id, version, file) {
+            Ok(s) => s,
+            Err(InteractError::Malformed) => {
+                eprintln!("The downloaded string {file} for {id}@{version} is malformed");
+                std::process::exit(343);
+            }
+            Err(InteractError::HttpCode(404)) => {
+                eprintln!(
+                    "File {file} for {id}@{version} is {}!",
+                    "not found".if_supports_color(Stderr, |text| text.bright_red())
+                );
+                std::process::exit(12);
+            }
+            Err(InteractError::HttpCode(code)) => {
+                eprintln!("Http error {code} for {file} for {id}@{version}.");
+                std::process::exit(13);
+            }
+            Err(err) => {
+                eprintln!("Connection error.\n{err}");
+                std::process::exit(14);
+            }
+        }
+    }
+
+    fn fetch_blob(&self, file: &str) -> Vec<u8> {
+        let id = self
+            .data
+            .id
+            .as_ref()
+            .expect("Failed to get id, but it should have been guaranteed.");
+        let version = self
+            .data
+            .version
+            .as_ref()
+            .expect("Failed to get version, but it should have been guaranteed.");
+
+        match self.interact.get_blob(id, version, file) {
+            Ok(s) => s,
+            Err(InteractError::Malformed) => {
+                eprintln!("The downloaded blob {file} for {id}@{version} is malformed");
+                std::process::exit(343);
+            }
+            Err(InteractError::HttpCode(404)) => {
+                eprintln!(
+                    "File {file} for {id}@{version} is {}!",
+                    "not found".if_supports_color(Stderr, |text| text.bright_red())
+                );
+                std::process::exit(24);
+            }
+            Err(InteractError::HttpCode(code)) => {
+                eprintln!("Http error {code} for {file} for {id}@{version}.");
+                std::process::exit(25);
+            }
+            Err(err) => {
+                eprintln!("Connection error.\n{err}");
+                std::process::exit(26);
+            }
+        }
+    }
+
+    #[cfg(feature = "sig")]
+    fn verify_file(&self, file: &str, config: &Config, sig_file: &str, raw_file: &str) {
+        use base64::Engine;
+        use minisign::{PublicKeyBox, SignatureBox};
+
+        let id = self
+            .data
+            .id
+            .as_ref()
+            .expect("Failed to get id, but it should have been guaranteed.");
+        let version = self
+            .data
+            .version
+            .as_ref()
+            .expect("Failed to get version, but it should have been guaranteed.");
+
+        let sig = &self.fetch_str(sig_file);
+        let signature_box = SignatureBox::from_string(sig).expect("Signature was malformed.");
+
+        if config.sigs.contains_key(&config.index)
+            && !config.sigs.get(&config.index).unwrap().is_empty()
+        {
+            let mut verified = false;
+            let keys = config.sigs.get(&config.index).unwrap();
+            for key in keys {
+                let raw_key = base64::engine::general_purpose::STANDARD
+                    .decode(key)
+                    .unwrap_or_else(|_| panic!("A key for {} is malformed base64.", config.index));
+                let str_key = String::from_utf8(raw_key).expect("Public key was not utf8.");
+                let pk_box =
+                    PublicKeyBox::from_string(&str_key).expect("Public key was malformed.");
+                let pk = pk_box
+                    .into_public_key()
+                    .expect("Could not convert public key box into public key");
+
+                let reader = std::io::Cursor::new(raw_file.as_bytes());
+                if minisign::verify(&pk, &signature_box, reader, true, false, false).is_ok() {
+                    verified = true;
+                    break;
+                }
+            }
+
+            if !verified {
+                eprintln!(
+                    "{} verify {file} for {id}@{version}.",
+                    "Could not".if_supports_color(Stderr, |text| text.bright_red())
+                );
+                if config.force_verify {
+                    std::process::exit(224);
+                }
+            }
+            else {
+                eprintln!(
+                    "{} {file} for {id}@{version} with minisign.",
+                    "Verified".if_supports_color(Stderr, |text| text.bright_blue())
+                );
+            }
+        }
+        else if config.force_verify {
+            eprintln!(
+                "Could not force sig for index {}. Missing public key.",
+                config.index
+            );
+            std::process::exit(224);
+        }
+    }
+
+    fn verify_archive(&self, config: &Config, hashes: &HashesFileImm, bytes: &[u8]) {
+        if let Some(blob) = hashes.hashes.get(&config.target) {
+            let hashes = &blob.archive;
+            self.verify_bytes(hashes, &format!("{} archive", &config.target), bytes)
+        }
+    }
+
+    pub fn verify_bin(&self, config: &Config, bin_name: &str, bytes: &[u8]) {
+        let id = self
+            .data
+            .id
+            .as_ref()
+            .expect("Failed to get id, but it should have been guaranteed.");
+        let version = self
+            .data
+            .version
+            .as_ref()
+            .expect("Failed to get version, but it should have been guaranteed.");
+        let hashes = self
+            .data
+            .hashes
+            .as_ref()
+            .expect("Failed to get hashes, but it should have been guaranteed.");
+
+        if let Some(blob) = hashes.hashes.get(&config.target) {
+            match &blob.bins.get(bin_name) {
+                Some(blob) => self.verify_bytes(blob, &format!("{bin_name} binary"), bytes),
+                None => {
+                    eprintln!("Could not find {bin_name} hash for {id}@{version}.");
+                    std::process::exit(229);
                 }
             }
         }
     }
+
+    fn verify_bytes(&self, hashes: &Hashes, item: &str, bytes: &[u8]) {
+        let id = self
+            .data
+            .id
+            .as_ref()
+            .expect("Failed to get id, but it should have been guaranteed.");
+        let version = self
+            .data
+            .version
+            .as_ref()
+            .expect("Failed to get version, but it should have been guaranteed.");
+
+        #[cfg(feature = "sha3")]
+        {
+            use sha3::{Digest, Sha3_256, Sha3_512};
+
+            // sha3_512
+            if let Some(sha_hash) = hashes.get(&HashType::Sha3_512) {
+                let mut hasher = Sha3_512::new();
+                hasher.update(bytes);
+                let hash: Vec<u8> = hasher.finalize().to_vec();
+                let hash = hex::encode(hash);
+
+                if !(hash.eq(sha_hash)) {
+                    eprintln!("sha3_512 hashes do not match for {item}. {sha_hash} != {hash}");
+                    std::process::exit(3512);
+                }
+
+                eprintln!(
+                    "{} {item} for {id}@{version} with sha3_512.",
+                    "Verified".if_supports_color(Stderr, |text| text.bright_blue())
+                );
+                return;
+            }
+
+            // sha3_256
+            if let Some(sha_hash) = hashes.get(&HashType::Sha3_256) {
+                let mut hasher = Sha3_256::new();
+                hasher.update(bytes);
+                let hash: Vec<u8> = hasher.finalize().to_vec();
+                let hash = hex::encode(hash);
+
+                if !(hash.eq(sha_hash)) {
+                    eprintln!("sha3_256 hashes do not match for {item}. {sha_hash} != {hash}");
+                    std::process::exit(3512);
+                }
+
+                eprintln!(
+                    "{} {item} for {id}@{version} with sha3_256.",
+                    "Verified".if_supports_color(Stderr, |text| text.bright_blue())
+                );
+                return;
+            }
+        }
+
+        #[cfg(feature = "sha2")]
+        {
+            use sha2::{Digest, Sha256, Sha512};
+
+            // sha512
+            if let Some(sha_hash) = hashes.get(&HashType::Sha512) {
+                let mut hasher = Sha512::new();
+                hasher.update(bytes);
+                let hash: Vec<u8> = hasher.finalize().to_vec();
+                let hash = hex::encode(hash);
+
+                if !(hash.eq(sha_hash)) {
+                    eprintln!("sha512 hashes do not match for {item}. {sha_hash} != {hash}");
+                    std::process::exit(512);
+                }
+
+                eprintln!(
+                    "{} {item} for {id}@{version} with sha512.",
+                    "Verified".if_supports_color(Stderr, |text| text.bright_blue())
+                );
+                return;
+            }
+
+            // sha256
+            if let Some(sha_hash) = hashes.get(&HashType::Sha256) {
+                let mut hasher = Sha256::new();
+                hasher.update(bytes);
+                let hash: Vec<u8> = hasher.finalize().to_vec();
+                let hash = hex::encode(hash);
+
+                if !(hash.eq(sha_hash)) {
+                    eprintln!("sha256 hashes do not match for {item}. {sha_hash} != {hash}");
+                    std::process::exit(256);
+                }
+
+                eprintln!(
+                    "{} {item} for {id}@{version} with sha256.",
+                    "Verified".if_supports_color(Stderr, |text| text.bright_blue())
+                );
+                return;
+            }
+        }
+
+        eprintln!("Could not verify downloaded {item} for {id}@{version}.");
+        #[cfg(any(feature = "sha2", feature = "sha3"))]
+        std::process::exit(228);
+    }
 }
diff --git a/src/interact/github_private.rs b/src/interact/github_private.rs
index 75b1de8..0d36cb3 100644
--- a/src/interact/github_private.rs
+++ b/src/interact/github_private.rs
@@ -16,58 +16,13 @@ impl GithubPrivate {
     }
 }
 impl Interact for GithubPrivate {
-    fn pre_url(&self, id: &str, version: &str, target: &str) -> String {
-        let _ = self.auth_token;
-
-        format!(
-            "https://{}/releases/download/{id}-{version}/{target}",
-            self.slug
-        )
-    }
-
     fn get_latest(&self, id: &str) -> Result<String, InteractError> {
-        let url = format!("https://{}/releases/download/stable-index/{id}", self.slug);
-        call(&self.agent, &url)
+        todo!()
     }
-
-    fn get_hash(&self, id: &str, version: &str, target: &str) -> Result<String, InteractError> {
-        let url = format!("{}.sha256", self.pre_url(id, version, target));
-        call(&self.agent, &url)
-    }
-
-    fn get_tar(&self, id: &str, version: &str, target: &str) -> Result<Vec<u8>, InteractError> {
-        let url = format!("{}.tar.gz", self.pre_url(id, version, target));
-        let mut bytes = Vec::new();
-        match self.agent.get(&url).call() {
-            Ok(response) => {
-                response
-                    .into_reader()
-                    .read_to_end(&mut bytes)
-                    .map_err(|_| InteractError::Malformed)?;
-            }
-            Err(Error::Status(code, _)) => return Err(InteractError::HttpCode(code)),
-            Err(_) => return Err(InteractError::ConnectionError),
-        }
-
-        Ok(bytes)
+    fn get_str(&self, id: &str, version: &str, file_name: &str) -> Result<String, InteractError> {
+        todo!()
     }
-
-    fn get_report(&self, id: &str, version: &str, name: &str) -> Result<String, InteractError> {
-        let url = format!(
-            "https://{}/releases/download/{id}-{version}/{name}.report",
-            self.slug
-        );
-        call(&self.agent, &url)
+    fn get_blob(&self, id: &str, version: &str, file_name: &str) -> Result<Vec<u8>, InteractError> {
+        todo!()
     }
 }
-
-fn call(agent: &Agent, url: &str) -> Result<String, InteractError> {
-    return match agent.get(url).call() {
-        Ok(res) => {
-            let s = res.into_string().map_err(|_| InteractError::Malformed)?;
-            Ok(s.trim().to_string())
-        }
-        Err(Error::Status(code, _)) => Err(InteractError::HttpCode(code)),
-        Err(_) => Err(InteractError::ConnectionError),
-    };
-}
diff --git a/src/interact/github_public.rs b/src/interact/github_public.rs
index de32b0c..697013a 100644
--- a/src/interact/github_public.rs
+++ b/src/interact/github_public.rs
@@ -12,30 +12,31 @@ impl GithubPublic {
             slug: slug.to_string(),
         }
     }
-}
-impl Interact for GithubPublic {
-    fn pre_url(&self, id: &str, version: &str, target: &str) -> String {
+
+    fn pre_url(&self, id: &str, version: &str, file: &str) -> String {
         format!(
-            "https://{}/releases/download/{id}-{version}/{target}",
+            "https://{}/releases/download/{id}-{version}/{file}",
             self.slug
         )
     }
-
+}
+impl Interact for GithubPublic {
     fn get_latest(&self, id: &str) -> Result<String, InteractError> {
         let url = format!("https://{}/releases/download/stable-index/{id}", self.slug);
         call(&self.agent, &url)
     }
 
-    fn get_hash(&self, id: &str, version: &str, target: &str) -> Result<String, InteractError> {
-        let url = format!("{}.sha256", self.pre_url(id, version, target));
+    fn get_str(&self, id: &str, version: &str, file_name: &str) -> Result<String, InteractError> {
+        let url = self.pre_url(id, version, file_name);
         call(&self.agent, &url)
     }
 
-    fn get_tar(&self, id: &str, version: &str, target: &str) -> Result<Vec<u8>, InteractError> {
-        let url = format!("{}.tar.gz", self.pre_url(id, version, target));
+    fn get_blob(&self, id: &str, version: &str, file_name: &str) -> Result<Vec<u8>, InteractError> {
+        let url = self.pre_url(id, version, file_name);
         let mut bytes = Vec::new();
         match self.agent.get(&url).call() {
             Ok(response) => {
+                //TODO: Allow limiting of size.
                 response
                     .into_reader()
                     .read_to_end(&mut bytes)
@@ -47,14 +48,6 @@ impl Interact for GithubPublic {
 
         Ok(bytes)
     }
-
-    fn get_report(&self, id: &str, version: &str, name: &str) -> Result<String, InteractError> {
-        let url = format!(
-            "https://{}/releases/download/{id}-{version}/{name}.report",
-            self.slug
-        );
-        call(&self.agent, &url)
-    }
 }
 
 fn call(agent: &Agent, url: &str) -> Result<String, InteractError> {
diff --git a/src/interact/mod.rs b/src/interact/mod.rs
index 78944fa..e1b3a67 100644
--- a/src/interact/mod.rs
+++ b/src/interact/mod.rs
@@ -1,3 +1,4 @@
+use owo_colors::{OwoColorize, Stream::Stderr};
 use ureq::Agent;
 
 #[cfg(feature = "github-private")]
@@ -17,29 +18,8 @@ pub enum InteractError {
     // Unknown,
 }
 
-pub fn create_interact(
-    input: &Option<String>,
-    _auth: &Option<String>,
-    agent: Agent,
-) -> Box<dyn Interact> {
-    // Default
-    if input.is_none() {
-        #[cfg(feature = "github-public")]
-        {
-            return Box::new(github_public::GithubPublic::new(
-                agent,
-                "github.com/cargo-prebuilt/index",
-            ));
-        }
-        #[cfg(not(feature = "github-public"))]
-        {
-            println!("Using the default index requires the github-public feature!");
-            std::process::exit(-220);
-        }
-    }
-
-    let input = input.clone().unwrap();
-
+// TODO: Remove _ from auth.
+pub fn create_interact(input: String, _auth: Option<&String>, agent: Agent) -> Box<dyn Interact> {
     // Github public
     if input.starts_with("gh-pub:") {
         #[cfg(feature = "github-public")]
@@ -47,13 +27,16 @@ pub fn create_interact(
             let url = input
                 .get(7..input.len())
                 .expect("Missing url after gh-pub:");
-            println!("Using index https://{url}.");
+            eprintln!(
+                "{} index https://{url}.",
+                "Using".if_supports_color(Stderr, |text| text.bright_cyan())
+            );
             return Box::new(github_public::GithubPublic::new(agent, url));
         }
         #[cfg(not(feature = "github-public"))]
         {
-            println!("Using this index ({input}) requires the github-public feature!");
-            std::process::exit(-220);
+            eprintln!("Using this index ({input}) requires the github-public feature!");
+            std::process::exit(220);
         }
     }
 
@@ -64,29 +47,29 @@ pub fn create_interact(
             let url = input
                 .get(7..input.len())
                 .expect("Missing url after gh-pri:");
-            println!("Using index https://{url}.");
+            eprintln!(
+                "{} index https://{url}.",
+                "Using".if_supports_color(Stderr, |text| text.bright_cyan())
+            );
             return Box::new(github_private::GithubPrivate::new(
                 agent,
-                auth.clone().expect("Need auth token for private index."),
+                _auth.expect("Need auth token for private index.").clone(),
                 url,
             ));
         }
         #[cfg(not(feature = "github-private"))]
         {
-            println!("Using this index ({input}) requires the github-private feature!");
-            std::process::exit(-220);
+            eprintln!("Using this index ({input}) requires the github-private feature!");
+            std::process::exit(220);
         }
     }
 
-    println!("This index ({input}) is not supported.");
-    std::process::exit(-221);
+    eprintln!("This index ({input}) is not supported or malformed.");
+    std::process::exit(221);
 }
 
 pub trait Interact {
-    fn pre_url(&self, id: &str, version: &str, target: &str) -> String;
-
     fn get_latest(&self, id: &str) -> Result<String, InteractError>;
-    fn get_hash(&self, id: &str, version: &str, target: &str) -> Result<String, InteractError>;
-    fn get_tar(&self, id: &str, version: &str, target: &str) -> Result<Vec<u8>, InteractError>;
-    fn get_report(&self, id: &str, version: &str, name: &str) -> Result<String, InteractError>;
+    fn get_str(&self, id: &str, version: &str, file_name: &str) -> Result<String, InteractError>;
+    fn get_blob(&self, id: &str, version: &str, file_name: &str) -> Result<Vec<u8>, InteractError>;
 }
diff --git a/src/main.rs b/src/main.rs
index 6760f82..c53694b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,89 +1,57 @@
-mod args;
-mod conf_file;
+mod config;
+mod data;
 mod get;
 mod interact;
-#[cfg(test)]
-mod test;
 
 use flate2::read::GzDecoder;
-use home::cargo_home;
-use owo_colors::{OwoColorize, Stream::Stdout};
-use sha2::{Digest, Sha256};
-use std::{env, fs, fs::create_dir_all, path::Path, str, string::ToString};
+use owo_colors::{OwoColorize, Stream::Stderr};
+use std::{
+    env,
+    fs::{self, create_dir_all, File},
+    io::{Read, Write},
+    path::Path,
+    str,
+};
 use tar::Archive;
 
-#[cfg(all(feature = "rustls", feature = "native"))]
-compile_error!("rustls and native features are mutually exclusive and cannot be enabled together.");
-
-#[cfg(not(any(feature = "github-public", feature = "github-private")))]
-compile_error!("You have not enabled any of the indexes. Try enabling the 'indexes' feature, or enabled one of the indexes.");
+use crate::get::Fetcher;
 
+static DEFAULT_INDEX: &str = "gh-pub:github.com/cargo-prebuilt/index";
 static TARGET: &str = env!("TARGET");
 
 fn main() -> Result<(), String> {
-    // Bypass bpaf, print version, then exit.
-    let args: Vec<String> = env::args().collect();
-    if args.contains(&"--version".to_string()) || args.contains(&"-v".to_string()) {
-        println!(env!("CARGO_PKG_VERSION"));
-        std::process::exit(0);
-    }
+    should_error();
 
-    let mut args = args::parse_args();
+    let config = config::get();
     #[cfg(debug_assertions)]
-    dbg!(&args);
-
-    // Try to get index from config file.
-    if !args.ci && args.index.is_none() {
-        args.index = conf_file::get_index();
-    }
-
-    let args = args;
+    dbg!(&config);
 
-    if args.colors {
-        owo_colors::set_override(true);
+    if !config.no_create_path && create_dir_all(&config.path).is_err() {
+        eprintln!("Could not create the directories {:?}.", config.path);
+        std::process::exit(44);
     }
-    if args.no_colors {
-        owo_colors::set_override(false);
+    else if !Path::new(&config.path).exists() {
+        eprintln!("Directories do not exist! {:?}.", config.path);
+        std::process::exit(45);
     }
 
-    let target = args.target.as_str();
-
-    let prebuilt_bin = args.path.clone().unwrap_or_else(|| {
-        let mut cargo_home = cargo_home().expect("Could not find cargo home directory, please set CARGO_HOME or PREBUILT_PATH, or use --path");
-        if !cargo_home.ends_with("bin") {
-            cargo_home.push("bin");
-        }
-        cargo_home
-    });
-
-    if !args.no_create_path && create_dir_all(&prebuilt_bin).is_err() {
-        println!("Could not create the directories {prebuilt_bin:?}.");
-        std::process::exit(-44);
+    if !config.no_create_path && create_dir_all(&config.report_path).is_err() {
+        eprintln!("Could not create the directories {:?}.", config.report_path);
+        std::process::exit(44);
     }
-    else if !Path::new(&prebuilt_bin).exists() {
-        println!("Directories do not exist! {prebuilt_bin:?}.");
-        std::process::exit(-45);
+    else if !Path::new(&config.report_path).exists() {
+        eprintln!("Directories do not exist! {:?}.", config.report_path);
+        std::process::exit(45);
     }
 
     // Build ureq agent
-    #[cfg(feature = "native")]
-    let agent = ureq::AgentBuilder::new().tls_connector(std::sync::Arc::new(
-        native_tls::TlsConnector::new().expect("Could not create TlsConnector"),
-    ));
-    #[cfg(feature = "rustls")]
-    let agent = ureq::AgentBuilder::new();
-
-    let agent = agent
-        .https_only(true)
-        .user_agent(format!("cargo-prebuilt_cli {}", env!("CARGO_PKG_VERSION")).as_str())
-        .build();
+    let agent = create_agent();
 
-    // Create interactor, which handles all of the interacts with indexes
-    let interact = interact::create_interact(&args.index, &args.auth, agent);
-    let interact = interact.as_ref();
+    // Create Fetcher which is used to fetch items from index.
+    let mut fetcher = Fetcher::new(&config, agent);
 
     // Get pkgs
-    let pkgs: Vec<&str> = args.pkgs.split(',').collect();
+    let pkgs: Vec<&str> = config.pkgs.split(',').collect();
     for pkg in pkgs {
         let mut id = pkg;
         let mut version = None; // None will pull the latest version
@@ -94,72 +62,127 @@ fn main() -> Result<(), String> {
             version = Some(j)
         }
 
-        // Get latest version
-        let version = match version {
-            Some(v) => v.to_string(),
-            None => get::latest_version(interact, id),
-        };
-        let version = version.as_str();
-
-        // Download hash
-        let sha_hash = get::hash(interact, id, version, target);
-
-        // Download tarball
-        let tar_bytes = get::tar(interact, id, version, target);
+        // Init fetcher for this crate and get latest version if needed
+        fetcher.load(id, version);
 
-        // Check hash
-        let mut hasher = Sha256::new();
-        hasher.update(&tar_bytes);
-        let hash: Vec<u8> = hasher.finalize().to_vec();
-        let hash = hex::encode(hash);
+        // Get version that fetcher is using
+        let version = fetcher.get_version();
 
-        if !(hash.eq(&sha_hash)) {
-            println!("Hashes do not match.");
-            std::process::exit(-256);
-        }
+        // Download and hash tar
+        let tar_bytes = fetcher.download(&config);
 
         // Extract Tar
         let reader = std::io::Cursor::new(tar_bytes);
         let mut archive = Archive::new(GzDecoder::new(reader));
         match archive.entries() {
             Ok(es) => {
-                println!(
-                    "{} {id} {version}...",
-                    "Extracting".if_supports_color(Stdout, |text| text.bright_blue())
+                eprintln!(
+                    "{} {id}@{version}...",
+                    "Extracting".if_supports_color(Stderr, |text| text.bright_blue())
                 );
 
                 for e in es {
-                    let mut e = e.expect("Malformed entry.");
-
-                    let mut path = prebuilt_bin.clone();
-                    path.push(e.path().expect("Could not extract path from tar."));
-
-                    e.unpack(&path)
-                        .expect("Could not extract binaries from downloaded tar archive");
-
-                    let abs = fs::canonicalize(path).expect("Could not canonicalize install path");
-                    println!(
+                    let mut e = e.expect("Malformed entry in tarball.");
+
+                    let mut blob_data = Vec::new();
+                    e.read_to_end(&mut blob_data)
+                        .expect("Could not extract binary from archive.");
+
+                    let bin_path = e.path().expect("Could not extract path from archive.");
+                    let str_name = bin_path
+                        .clone()
+                        .into_owned()
+                        .into_os_string()
+                        .into_string()
+                        .expect("Archive has non utf-8 path.");
+
+                    // Verify each binary in archive
+                    fetcher.verify_bin(&config, &str_name, &blob_data);
+
+                    let mut path = config.path.clone();
+                    path.push(bin_path);
+
+                    let mut file =
+                        File::create(&path).expect("Could not open file to write binary to.");
+                    file.write_all(&blob_data)
+                        .expect("Could not write binary to file.");
+
+                    // Add exe permission on unix platforms.
+                    #[cfg(target_family = "unix")]
+                    {
+                        use std::os::unix::fs::PermissionsExt;
+                        fs::set_permissions(&path, fs::Permissions::from_mode(0o755))
+                            .expect("Could not set permissions.");
+                    }
+
+                    let abs = fs::canonicalize(path).expect("Could not canonicalize install path.");
+
+                    eprintln!(
                         "{} {abs:?}.",
-                        "Added".if_supports_color(Stdout, |text| text.bright_purple())
+                        "Installed".if_supports_color(Stderr, |text| text.bright_purple())
                     );
+
+                    // Print paths to stdout too, maybe so others can parse?
+                    println!("{abs:?}");
                 }
             }
             Err(_) => {
-                println!("Cannot get entries from downloaded tar.");
-                std::process::exit(-13);
+                eprintln!("Cannot get entries from downloaded tar.");
+                std::process::exit(13);
             }
         }
 
         // Reports
-        get::reports(interact, &args, &prebuilt_bin, id, version);
+        if !config.ci {
+            fetcher.reports(&config);
+        }
 
-        println!(
-            "{} {id} {version}.",
-            "Installed".if_supports_color(Stdout, |text| text.bright_green())
+        eprintln!(
+            "{} {id}@{version}.",
+            "Installed".if_supports_color(Stderr, |text| text.bright_green())
         );
+
+        // Prepare for next crate.
+        fetcher.reset();
     }
 
-    println!("{}", "Done!".if_supports_color(Stdout, |text| text.green()));
+    eprintln!("{}", "Done!".if_supports_color(Stderr, |text| text.green()));
 
     Ok(())
 }
+
+fn should_error() {
+    // Errors
+    #[cfg(not(any(feature = "native", feature = "rustls")))]
+    {
+        eprintln!("cargo-prebuilt only supports https and was built without the 'native' or 'rustls' feature.");
+        std::process::exit(400);
+    }
+    #[cfg(not(any(feature = "github-public", feature = "github-private")))]
+    {
+        eprintln!("cargo-prebuilt was not built with any indexes, try the 'indexes' feature.");
+        std::process::exit(222);
+    }
+}
+
+fn create_agent() -> ureq::Agent {
+    #[cfg(feature = "native")]
+    let agent = ureq::AgentBuilder::new().tls_connector(std::sync::Arc::new(
+        native_tls::TlsConnector::new().expect("Could not create TlsConnector"),
+    ));
+
+    #[cfg(feature = "rustls")]
+    let agent = ureq::AgentBuilder::new();
+
+    #[cfg(any(feature = "native", feature = "rustls"))]
+    let agent = agent
+        .https_only(true)
+        .user_agent(format!("cargo-prebuilt_cli {}", env!("CARGO_PKG_VERSION")).as_str())
+        .build();
+
+    // Allows for any feature set to be built for, even though this is unsupported.
+    #[cfg(not(any(feature = "native", feature = "rustls")))]
+    let agent = ureq::agent();
+
+    agent
+}


Test patch:
diff --git a/src/test.rs b/src/test.rs
deleted file mode 100644
index 8ab1fbe..0000000
--- a/src/test.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#[test]
-fn test() {
-    assert_eq!(1, 1)
-}
diff --git a/test/config_1.toml b/test/config_1.toml
new file mode 100644
index 0000000..7fc9533
--- /dev/null
+++ b/test/config_1.toml
@@ -0,0 +1,19 @@
+[prebuilt]
+target = "$TARGET"        # Target to download for
+index = "hg-pub:$INDEX"   # Index to use
+auth = "NULL"             # Index auth token
+path = "/prebuilt/bin"    # Absolute path to where the binaries will be installed
+report_path = "/prebuilt" # Absolute path to where the reports will be put
+no_create_path = false    # Do not create paths that do not exist
+reports = [               # Reports to download
+    "license",
+    "deps",
+    "audit",
+]
+color = true              # Should CLI colors be on or not
+hashes = ["sha256"]       # Hashes to use for verifying files downloaded
+force_verify = true
+
+[key.test]             # Add a public verifying key for an index
+index = "$INDEX"            # Index to add key for
+pub_key = "$PUBLIC_GPG_KEY" # Public verifying key for index
diff --git a/test/config_2.toml b/test/config_2.toml
new file mode 100644
index 0000000..a2ff86b
--- /dev/null
+++ b/test/config_2.toml
@@ -0,0 +1,2 @@
+[prebuilt]
+hashes = []
diff --git a/test/hashes_1.json b/test/hashes_1.json
new file mode 100644
index 0000000..4f415f1
--- /dev/null
+++ b/test/hashes_1.json
@@ -0,0 +1,1 @@
+{"hashes_version":"1","hashes":{"TARGET":{"archive":{"sha256":"HASH","sha512":"HASH?"},"bins":{"BINARY":{"sha256":"HASH","sha256":"HASH?"},"BINARY?":{"sha512":"HASH","sha512":"HASH?"}}},"TARGET?":{"archive":{"sha256":"HASH","sha512":"HASH?"},"bins":{"BINARY":{"sha256":"HASH","sha512":"HASH?"},"BINARY?":{"sha256":"HASH","sha512":"HASH?"}}}}}
\ No newline at end of file
diff --git a/test/hashes_2.json b/test/hashes_2.json
new file mode 100644
index 0000000..b9d70b6
--- /dev/null
+++ b/test/hashes_2.json
@@ -0,0 +1,1 @@
+{"hashes_version": "1", "hashes": {"s390x-unknown-linux-gnu": {"archive": {"sha256": "166f09e241ae53709b067c267ff679d15490c226a15a752b1f3de52054e0b1cd", "sha512": "2702112234c40b0bed64dfb029c6ce7b60c9360d78ca03f83a0a084b369baa1d91f6931528b0d876f4d62f10df36da7fc12c62fdcda01564a0693b41f857ddeb"}, "bins": {"cargo-prebuilt": {"sha256": "b63245ece2583119eb6779943f4c4568f814eb7cdebfdd397744ca45bd49b511", "sha512": "f605416137323256f6b5eb8de33f5e3fbac9b31dfd520bd383626d025fe202ebf8796b8e5235ad1cd6058428bfba6f7e665f95217f41992ef40f9bab53ab9dd7"}}}, "x86_64-apple-darwin": {"archive": {"sha256": "b9d09c6b2ae508a12b8072fc896c4b327d1d13b058996c81332aaa16800dc886", "sha512": "01e294c8112b4e6284d2253ff2810c4232c804f853f16a67532b48343bf8d5127f0fc3ac988db357c8ef997b2e23137e8a6521ad9329b8a8a10a0d43e7f7b44d"}, "bins": {"cargo-prebuilt": {"sha256": "8d466eacf8ec6a1e83da5e31fd180ffa2146810d6d866eff8a07609a46714078", "sha512": "fd307b6d2c7346549f9f151da98d44f7d2947897f96b79a9ec814388d15577b7791c6acf6d3cf70215df6d05d83ae3fdfd513657e74f14dc870662eeed630c42"}}}, "x86_64-unknown-netbsd": {"archive": {"sha256": "cc74d267d9091496fdfc3fc2bbb5d8d213c6831ce7f039358932c84a9eb4ba01", "sha512": "abd0258300af56ecc5fbba2c48b2064dea7b8945a21853d277565cbb6cb7a05f57ceb6aa27beb81337bea63531fcbda131215ec653a15b0d0fee1b3b7b40b5a2"}, "bins": {"cargo-prebuilt": {"sha256": "9b206a9057ed5150a83fe0c2784b846e91d19b139341b5467e0866454cf40abc", "sha512": "673b2bf77f58b881efd1a02767437f15d145d15ca25ddf412692a5c11fc6221530aa3d9c24f3250a4206fe27eca3c42d7cdca376262ed70c58d1377229f53572"}}}, "mips64-unknown-linux-muslabi64": {"archive": {"sha256": "4cb97dceec7b172ce50c53d94e8212983fa24cbe5515066c24049a5cda877cf7", "sha512": "deaa60bddfdea1674adba2406d266e4f4ed7992796a945fdbc116fd584be7a47c9d1a519bd594c40326cd25bf4560dd650ee39ace2fcd487e94a7ba8aa9d6768"}, "bins": {"cargo-prebuilt": {"sha256": "10afc7ef7e3f534408c8c001e6fe89e11d516168f9ba92b7cbb336b0af529412", "sha512": "e0b773c384ecb8e554f91f444f3137a0520f08a3fa993442b3bc6ea04aa0b971a6fc828ab0ad49aa7af5454d08931895065139b1278c05d8fd12a0a8d3e43a8b"}}}, "x86_64-unknown-illumos": {"archive": {"sha256": "6e82073fe303ef2224f4f9dc4ca73eb1e23132fe9f3d2871ad5c0e5a914ec5cd", "sha512": "9e258e7bfc815ce9c040e75e35c233da23dafb4ccb7f440bffa1409158c6666c30fce3cb4003bc7717b0369a52633a78aadbfda7280e859a0cd33cdb6f637d0e"}, "bins": {"cargo-prebuilt": {"sha256": "92aa4c4ed9d71ee769fb35a20294d01a2e69182aa1be33ca24f21f6adceaeade", "sha512": "884c16aff4b754a74609f85a5e4773a79d190479707fca78d3ca2f5cb0f4c9b1d279c440caf5a855a3c17b9d8b68ec40ee9cee90fa477271a5f0b77a2eb3786f"}}}, "x86_64-unknown-linux-gnu": {"archive": {"sha256": "3703ecd2e0adf0732ae9a22cfe0b6203c388e6d4cacad414c61291ea1ed517e8", "sha512": "ba9d52c34ad13e48fe6940af264eec45e96140acae4639b52970ba28180e8424487581554644e9d0e58375c3fb42ead61cf05d206f7ebd5cce95a4ca767ffad4"}, "bins": {"cargo-prebuilt": {"sha256": "5d3dfc5e6dab906f0ed070ec8636551ddc2c1dc8558dd8f8ce27e94951e8168f", "sha512": "a2693b651595a7b6e64f525eb468502c118493c90e1fc91807198209e0067e7b930d387b9647a742a0ec0d301f4e812f8dabe1246ed76f72b479d19593c0ca9b"}}}, "riscv64gc-unknown-linux-gnu": {"archive": {"sha256": "3afcef53420e1a7299339bcf7949db1f24ba8e590e503926a0c7d507a6f98f2f", "sha512": "6e23b2726fb78a77a9347598cfa87547b24dbb0f0331ae7c5a89f6616a0cd691397939277859493a177c71151bf526228003a8efc4587bdd1bfa182fe18db697"}, "bins": {"cargo-prebuilt": {"sha256": "cb4e78e242c9b2d7fc2b18cef5945a73c05069856dfd9e536c444fc56c73d685", "sha512": "4038eff1e2c4673bbc6d2dffdec7d0302dc1eb10ac8eb2efb5c392976d366e3de7e2416b7cb8c2de862f3b68aa72731194498d458263fbb199f5b1f879056a48"}}}, "x86_64-unknown-linux-musl": {"archive": {"sha256": "157daa935f72eaad1cb5273c60b3a29daa7ebe1172448865cafaa58c8deb85c4", "sha512": "7dac78ae76dfb2d630fd9e5ff00fe94e4792c0912fa737f2eba1a14442324e821d23ad22ea91766b80bca7149b600413db27cbacfe78a81430d06c1a17dec0e9"}, "bins": {"cargo-prebuilt": {"sha256": "4b4ef629e0db27a70ea4e8685fe815ba9acec5d43ebc357dfdb35d6196696018", "sha512": "39378008e9dc3d128d07bde1b09d555a3c0c0639af7740645d8a007105cc9520ac405966a213389b4d1bf37383da8539ae7dba25f1a2d1cf9e4c16614f44745f"}}}, "powerpc64le-unknown-linux-gnu": {"archive": {"sha256": "9dca5c6f52a4fd62cf90fb64e472e72569095d7968be16966da0120b656419a6", "sha512": "b88479e4162432e96e13e8639240ddab32ad41c81d3ba34c1d8dd95995653fce10d7344fc032908340d22b20c06485b253e0effe36f32b848ee9bb7a233da9f6"}, "bins": {"cargo-prebuilt": {"sha256": "1b1c4bb45b1cf1588a9341f3ab8a2e77e9e8765ac0486cfa8fc924fc25cfba03", "sha512": "f920df16b1aa8909ed38e1810cbd1fa25bd17936cec248f84ef784e53aaaff6d9ccd1da9fa256bb9e3bbf4f730b1a4727fbd1b4a82c31e88d2d5fd6529076695"}}}, "aarch64-apple-darwin": {"archive": {"sha256": "833e152ecbf22cbb500e865d79c1bbc5bb5514d5ac8ff6508b8622c289271cb5", "sha512": "41497234718f8c675b53ab80618b39c5fe185ffbdc475e310f981bf582e52bed21f6ff00ef55f99b5c80b429f09dbd9e77cac332c2f44c5ca2e640893e5aa79a"}, "bins": {"cargo-prebuilt": {"sha256": "bcfed92476d8596f03480d2dfe2d13df76d23ec34cfff3a3e76fd4904c7cc10d", "sha512": "dca9b4735c5d91f7ca4477d0eeeab5f901f317bab706fc172a2278eebda2dcf743854e687d2a868e8168c8fd2c9fa33f4cfff382efd31d216b84e93a55be85d7"}}}, "x86_64-sun-solaris": {"archive": {"sha256": "125205eb6ec8b40f41a53e75a7f99d8bb99b5250a3190eefa1b52e196b7e7528", "sha512": "b42531021f560aefd6e4b99cf4f1591b32ed70d42937c7e6323fc7f858b1a19c898102c4da4c674feec4fcccaec850b0e01df18e45eb8cc8c5bee3ad6c87076c"}, "bins": {"cargo-prebuilt": {"sha256": "3f68e02d32081e06494612d692880b5a70eeea3074901c486ed0be5619740cb1", "sha512": "7ff8e962f31d39e9ab63955a2b3db539f0c29e3a5de3a1c05a9ab373710e5930d60ec468c8359f332cd4462331f29cd4ce0fdca731bd058ec57545988a585290"}}}, "x86_64-unknown-freebsd": {"archive": {"sha256": "7aae3b1f526c33da1bc81df8f22ae4abde32802fc5f02ab4056bb91c6b5754c6", "sha512": "e6a48a2734a7801bf5f5fb465766713622fc11e4b6f710f1fe2767622cea2dfea9617ab428775422cbf5d30db054bda02657288ef8df9246a2a87be6fedd71bc"}, "bins": {"cargo-prebuilt": {"sha256": "203ed79b2141f29b172e1e6b7bc9692dedc7f804f6147e5f1bf7d488e3681e9b", "sha512": "8777a3857815075c6eb2b06ec7d80b05cba89046ea52a73f48f59ddf6dd9173a00ece8b62ddd7f4d72577086e659cb3c95198062747bd06eaccff704b6163f22"}}}, "mips64el-unknown-linux-muslabi64": {"archive": {"sha256": "0e42729119cd81cb95d8de93e9e2e6e0d7b5e20815e056e737a56bf13f69ced8", "sha512": "f9078633ae46db03619b97484f03e9c09e5285a8965feb8a66ad30dce62a590c2913560b37ce0d4b6ce29e6e1b3b10ca79bc4db7ad70f95e26d4b494f4c25ce7"}, "bins": {"cargo-prebuilt": {"sha256": "bba2d75584589c22f96b5b86420dc8d81e7dcfa436cb253b68330853ddb0bfb8", "sha512": "eb3703247c28c516d17f4d0a56944c441c010c5835ce1d941f9c68738b15e8dbb8b89713ddca5d61eb304c38fe9639c12a83a6884eab7c82a5bf15ec85b0952c"}}}, "mips64-unknown-linux-gnuabi64": {"archive": {"sha256": "71c34dd16fba75e3acd12c50d071e15e3973d6dfe582f748d21f173700bbfa7e", "sha512": "0f61ac9900ad9a7c0c7672b2d35e49f50d2aa5e175ab2241f3d0b6656e61eb7e8d377cc088d355dc056e99121e198b0b8ff514994d65b9d6141bb1d95766c3b8"}, "bins": {"cargo-prebuilt": {"sha256": "50865f1b27b6ffb7c7701af9a73973a2b450376d1605dd7dfae9e71d5d1b6786", "sha512": "d95924b5c6b50b786e1309534e3f8b2f901aeabb589ad090f4b1e6f7f50f7b0e0729ba5104f42bd222f8476c2a48e33be1924a7db114c87b0e2096dee882f1a6"}}}, "armv7-unknown-linux-musleabihf": {"archive": {"sha256": "32fa9b4adb49a0717afb0ea745567abd264c3f74734515db664996f13af39154", "sha512": "890c6b5e069393c979ad6b9dc2974b0257bea883fd8c843405e074494da5a660d72d26a0475b50d06fccb10b1af870764de7fc9b6161a54a9ab3e2a89b2e28c4"}, "bins": {"cargo-prebuilt": {"sha256": "eb216043fcb567f7c2063d657aa7381963b2eb39489b33b06cb99485262fcb60", "sha512": "a8ad9222a1110c6c50cd16589674b2bd9dc1a4e10ac2f2cc7ed65046bd52d72bf39c0e7235154ad7e0bbbe767ec4fd5dcda15ec67b01833639395e97631053af"}}}, "mips64el-unknown-linux-gnuabi64": {"archive": {"sha256": "58817f2caf6e1135ec1ad8dcf7a9094e112bafa33beedd9a4c228a0d427ab6d3", "sha512": "121e762753c29edc7608e12cb91c81400ac8e5b2847217b419928143805ba731fc638d5601bda82e6f44b05500b7893dd117233bbded4ab7f05d5a068b135315"}, "bins": {"cargo-prebuilt": {"sha256": "8a5f95db264f5242a3068b078b4fa6a5a11e64530f9b80349fa57e7d92ff3797", "sha512": "9f7b95cc4a91a33c5c9fda069269280cbf6024c70a831a4f6b2b3bc78457019f03a18fa04e1a789e76f97c8d66cc3a61c19bda1f4f7e994bd2098a425b378055"}}}, "aarch64-pc-windows-msvc": {"archive": {"sha256": "382457f0de7c1d882ad8af16999321ab3356636e50988f7e7020dbb1069f020e", "sha512": "37dc52cc10b4f491426672bfbcceaee17601a51b3c4d0b2728919b3972ac35fd1b269f19aa4c87b64cf6c94664be6693e2d4229b15a2a55fceb8e56c5bf3ac0b"}, "bins": {"cargo-prebuilt.exe": {"sha256": "637ee13084177de14013a0b652fd174cd9c2d61b2f2acd401ed2bfd8a3e97994", "sha512": "a232ea3db74db17a48532cdc88aee142ec5f4a0e25e91f5e6c3b2bdc62b68d751a1488cece85bdbf7691dd03fe018d1341648a7d9cf1a39f978e4594df0e2d48"}}}, "powerpc64-unknown-linux-gnu": {"archive": {"sha256": "c0e11e098f73321f35c51670e8fdcfc9dcbc0d98955771d5d84aaab1a5726256", "sha512": "a9e676cc1765a3780ae1814ee603f13be13c8c5e4a1a9b302db53b62d2bea9d9f61f151f8240a1b317b597a9056c60e45506b579dfc5f550441e2e9374191a79"}, "bins": {"cargo-prebuilt": {"sha256": "73fe8ce97a1ec402f3bfa0909ef269f02ecc46f193ba94cae575088e9cf0ebb7", "sha512": "b82750b0aefa3ec385b35d1d545c325178a54739207eaf7ebc1b254d7a0d6b13c42edc5ab0b71f9631918c455b990ee1205e02968a008cb697d90a83b05c6aef"}}}, "armv7-unknown-linux-gnueabihf": {"archive": {"sha256": "691496c129735e8b3002bc9d338ee0692bed00c040c9b35c3a68c4a8b80225ef", "sha512": "9c3d49615a84e745436fdd3eee68326e73141a9222c801abcf6a2e182809b0b500112c86249e3defb171f87a5ec75c0bfb19c041e32ebcccff4894e8fde094c9"}, "bins": {"cargo-prebuilt": {"sha256": "f578ee91cb748fcb9752bb396c6a5d5a0badc8c7fb93d64385c5431752df9bb6", "sha512": "377627632f4e637dcb6132ad7e547e7ba58780504e1b18cf2e7012d7d9caf926f9abf33ac1c48f83194dd75867898495babb7f87b29692269f5cb20698e7fa2c"}}}, "aarch64-unknown-linux-musl": {"archive": {"sha256": "402af27825367379014f0011c31f007b5b773a43201a4d278aa3f4c8c851838d", "sha512": "cd37d63f5252333a186c2e99a8aeea9358fdfefa4193c4e1908a716050182a72ad94187a87e6c64db9426775bf14a2487cc8968ee3f1cb57a03256cff6afaacf"}, "bins": {"cargo-prebuilt": {"sha256": "de8bc9767b4d214607dc12c0b23d5fa5d498bd90dd20934bde174ac65b9fb6b8", "sha512": "65c02d9b35b6b87cdef7873c76101a75f2114c1b2c333509e11f450ca93e6da368f06ab34c287ad7de57f67d0ef599a4807dce0bd7b918a58c7c9f86127198f1"}}}, "x86_64-pc-windows-msvc": {"archive": {"sha256": "631fbddae36c1d3000c24758de6ef6dc6cca46b067219c1e1c474e5a519e8cae", "sha512": "28d650922d9a1dd0683b4e55d960408380162cfa4b2be4f48a669c6f954911634d47c224415d212f9407c8433b7d963f82a51725437dafc369dcf81e27ea2da7"}, "bins": {"cargo-prebuilt.exe": {"sha256": "a7a133ce29bb618a2cce0722dc73ea1e0af3e8b33aa7f2b7035163c9fd2761eb", "sha512": "80a06a0cbcb29125b9d17db7b259793d56744b2b4738f573add8ee216c7f87f8359d60344a7aea2da47d31849ca9944152f6a83d7f3635033f8243649058b89c"}}}, "aarch64-unknown-linux-gnu": {"archive": {"sha256": "3cae21c0ec5466bb3fe08a119c9c2bde9fa686431e0af130b55275fcff35c0f3", "sha512": "127f95b7c5b0cd76df654b216d77536a3a2018e6367c4923b999fef062928ff92d31882cdd74104e04ceaea4aa1c4419501a3e6ddcfb6cc392b19586ebf3fbfe"}, "bins": {"cargo-prebuilt": {"sha256": "ba838511fe711453a6d4033277f97e11ca28131c9fd5f0ed591797b7f1dd9c67", "sha512": "b6e30765158ebfdb7f08e269f462b53886bdccec1d995dc1669f0cb7a2482dfeba42b296a0614d028e9b912cd497a1c806d1839828395f1c83abc23cf1db847c"}}}}}
\ No newline at end of file
diff --git a/test/info_1.json b/test/info_1.json
new file mode 100644
index 0000000..0c4cb24
--- /dev/null
+++ b/test/info_1.json
@@ -0,0 +1,1 @@
+{"info_version":"1","id":"CRATES.IO ID","version":"VERSION","license":"SPDX LICENSE","git":"GIT URL","description":"CRATES.IO DESCRIPTION","bins":["BINARY","BINARY?"],"info":{"META":"DATA"},"archive":{"compression":"gz","ext":"tar.gz"},"files":{"hash":"hashes.json","license":"license.report","deps":"deps.report","audit":"audit.report","sig_info":"info.json.sig"},"targets":["TARGET","TARGET?"]}
\ No newline at end of file
diff --git a/test/info_2.json b/test/info_2.json
new file mode 100644
index 0000000..a069ebd
--- /dev/null
+++ b/test/info_2.json
@@ -0,0 +1,1 @@
+{"info_version": "1", "id": "cargo-prebuilt", "version": "0.5.3", "license": "MIT", "git": "https://github.com/cargo-prebuilt/cargo-prebuilt", "description": "Download prebuilt crate binaries for many different platforms", "bins": ["cargo-prebuilt"], "info": {"rustc_version_guess": "1.70.0 (90c541806 2023-05-31)", "index_publish_date": "2023-06-29", "features_apple": "None", "features_linux": "None", "features_windows": "None", "no_default_features_apple": "False", "no_default_features_linux": "False", "no_default_features_windows": "False"}, "archive": {"compression": "gz", "ext": "tar.gz"}, "files": {"hash": "hashes.json", "license": "license.report", "deps": "deps.report", "audit": "audit.report"}, "targets": ["s390x-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-netbsd", "mips64-unknown-linux-muslabi64", "x86_64-unknown-illumos", "x86_64-unknown-linux-gnu", "riscv64gc-unknown-linux-gnu", "x86_64-unknown-linux-musl", "powerpc64le-unknown-linux-gnu", "aarch64-apple-darwin", "x86_64-sun-solaris", "x86_64-unknown-freebsd", "mips64el-unknown-linux-muslabi64", "mips64-unknown-linux-gnuabi64", "armv7-unknown-linux-musleabihf", "mips64el-unknown-linux-gnuabi64", "aarch64-pc-windows-msvc", "powerpc64-unknown-linux-gnu", "armv7-unknown-linux-gnueabihf", "aarch64-unknown-linux-musl", "x86_64-pc-windows-msvc", "aarch64-unknown-linux-gnu"]}
\ No newline at end of file
diff --git a/test/pubdata.pub b/test/pubdata.pub
new file mode 100644
index 0000000..f9f3bfb
--- /dev/null
+++ b/test/pubdata.pub
@@ -0,0 +1,2 @@
+untrusted comment: minisign public key BA2C204DF8BA67FE
+RWT+Z7r4TSAsutDuNpKn2uvyHHzG1vI4P8uLoBaS8yG8HYnGHznJjmQE
diff --git a/test/pubdata.test b/test/pubdata.test
new file mode 100644
index 0000000..d5f404e
--- /dev/null
+++ b/test/pubdata.test
@@ -0,0 +1,1 @@
+Minisign ftw
diff --git a/test/pubdata.test.minisig b/test/pubdata.test.minisig
new file mode 100644
index 0000000..16ebcc7
--- /dev/null
+++ b/test/pubdata.test.minisig
@@ -0,0 +1,4 @@
+untrusted comment: signature from minisign secret key
+RUT+Z7r4TSAsugF2IFrMBTpuV8BWxEkPALdv3zANIbA2wJymAD0m+xIJq+bfEj3sDSgA+G4rqkDFp76pekI8Hmf58cCCO0w0MwU=
+trusted comment: timestamp:1688330584	file:pubdata.test	hashed
+i8/+OB/I7BSmGG0o25iK4prLAu61br0qT4ghJYor7DFwaEZtsnde5gsApLzKXEn3bF87qiGLrp2h99IWMnRNCA==