diff --git a/CHANGELOG.md b/CHANGELOG.md index 5600cc9d19af375d545283a115a888c7162c3222..70ee44bba3095f597016b6ca4f7a6ddf8be2a5a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Revision history for gbs-downloader +## 0.2.0.0 -- YYYY-MM-DD + +* The download APIs now only send requests to a storage server after that + storage server is authenticated using information from the NURL. + ## 0.1.0.0 -- 2023-08-17 * First version. Released on an unsuspecting world. diff --git a/README.md b/README.md index 56fb22350bd927d34024a37b78004851baa5ad4b..2d547696975d630829003c0601ec09f79a289fc9 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ It aims for bit-for-bit compatibility with the original Python implementation. ### What is the current state? * It can download immutable and mutable shares from Great Black Swamp storage servers. - * It *does not* cryptographically verify the identity of servers it communicates with. + * It cryptographically verifies the identity of servers it communicates with. * It can interpret, decode, and decrypt the data for CHK- and SDMF-encoded shares to recover the plaintext. ## Why does it exist? diff --git a/flake.lock b/flake.lock index 39fc93c0c8f78ccc7a8f949aca810a342d90b372..7f3bf2f04898badebc813d64ce88c7ece00297dc 100644 --- a/flake.lock +++ b/flake.lock @@ -112,6 +112,22 @@ "type": "github" } }, + "flake-compat_8": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "locked": { "lastModified": 1667395993, @@ -143,12 +159,15 @@ } }, "flake-utils_11": { + "inputs": { + "systems": "systems_2" + }, "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "lastModified": 1681202837, + "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "owner": "numtide", "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "rev": "cfacdce06f30d2b68473a46042957675eebb3401", "type": "github" }, "original": { @@ -173,6 +192,21 @@ } }, "flake-utils_13": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_14": { "locked": { "lastModified": 1676283394, "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=", @@ -187,7 +221,22 @@ "type": "github" } }, - "flake-utils_14": { + "flake-utils_15": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_16": { "locked": { "lastModified": 1676283394, "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=", @@ -218,15 +267,12 @@ } }, "flake-utils_3": { - "inputs": { - "systems": "systems" - }, "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", "owner": "numtide", "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", "type": "github" }, "original": { @@ -251,12 +297,15 @@ } }, "flake-utils_5": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "lastModified": 1681202837, + "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "owner": "numtide", "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "rev": "cfacdce06f30d2b68473a46042957675eebb3401", "type": "github" }, "original": { @@ -311,15 +360,12 @@ } }, "flake-utils_9": { - "inputs": { - "systems": "systems_2" - }, "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", + "lastModified": 1676283394, + "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=", "owner": "numtide", "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", + "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073", "type": "github" }, "original": { @@ -353,7 +399,7 @@ "gitignore_2": { "inputs": { "nixpkgs": [ - "tahoe-directory", + "tahoe-chk", "hs-flake-utils", "pre-commit-hooks", "nixpkgs" @@ -377,7 +423,6 @@ "inputs": { "nixpkgs": [ "tahoe-directory", - "tahoe-capabilities", "hs-flake-utils", "pre-commit-hooks", "nixpkgs" @@ -401,7 +446,7 @@ "inputs": { "nixpkgs": [ "tahoe-directory", - "tahoe-chk", + "tahoe-capabilities", "hs-flake-utils", "pre-commit-hooks", "nixpkgs" @@ -424,8 +469,7 @@ "gitignore_5": { "inputs": { "nixpkgs": [ - "tahoe-directory", - "tahoe-ssk", + "tahoe-great-black-swamp", "hs-flake-utils", "pre-commit-hooks", "nixpkgs" @@ -448,9 +492,7 @@ "gitignore_6": { "inputs": { "nixpkgs": [ - "tahoe-directory", "tahoe-ssk", - "tahoe-capabilities", "hs-flake-utils", "pre-commit-hooks", "nixpkgs" @@ -473,7 +515,32 @@ "gitignore_7": { "inputs": { "nixpkgs": [ - "tahoe-great-black-swamp", + "tahoe-ssk", + "tahoe-capabilities", + "hs-flake-utils", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gitignore_8": { + "inputs": { + "nixpkgs": [ + "tahoe-ssk", + "tahoe-chk", "hs-flake-utils", "pre-commit-hooks", "nixpkgs" @@ -521,11 +588,11 @@ "pre-commit-hooks": "pre-commit-hooks_2" }, "locked": { - "lastModified": 1686149618, - "narHash": "sha256-/IHWacNutk3tklouWOgClp7FnOH+Yk6If13kKJMSEi8=", + "lastModified": 1677773826, + "narHash": "sha256-xJmOtHugr4k2zNhP/AF6JdIUnIEyM+TEspLn2n5kloc=", "ref": "main", - "rev": "49696f704eb965f57d729871c6d450ac0aff2b68", - "revCount": 12, + "rev": "d3a83fdd9563546ca41771186427638e685a2e2b", + "revCount": 9, "type": "git", "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git" }, @@ -542,11 +609,11 @@ "pre-commit-hooks": "pre-commit-hooks_3" }, "locked": { - "lastModified": 1681762240, - "narHash": "sha256-+PLx9xHBvV70dA7Gy/+YTH1w3PcSOrGV0z0rGxts8jU=", + "lastModified": 1692187439, + "narHash": "sha256-m7c4EPFWmB1OmV3dSYQk2qtXR53xOjZdLCjMtzHSK34=", "ref": "main", - "rev": "a51e591b7fdf8881ac0237452691df7b1aceecd3", - "revCount": 10, + "rev": "408f3deab2e2f6ae60349776dde02c44f71fb386", + "revCount": 16, "type": "git", "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git" }, @@ -563,11 +630,11 @@ "pre-commit-hooks": "pre-commit-hooks_4" }, "locked": { - "lastModified": 1677773826, - "narHash": "sha256-xJmOtHugr4k2zNhP/AF6JdIUnIEyM+TEspLn2n5kloc=", + "lastModified": 1681762240, + "narHash": "sha256-+PLx9xHBvV70dA7Gy/+YTH1w3PcSOrGV0z0rGxts8jU=", "ref": "main", - "rev": "d3a83fdd9563546ca41771186427638e685a2e2b", - "revCount": 9, + "rev": "a51e591b7fdf8881ac0237452691df7b1aceecd3", + "revCount": 10, "type": "git", "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git" }, @@ -584,11 +651,11 @@ "pre-commit-hooks": "pre-commit-hooks_5" }, "locked": { - "lastModified": 1681762240, - "narHash": "sha256-+PLx9xHBvV70dA7Gy/+YTH1w3PcSOrGV0z0rGxts8jU=", + "lastModified": 1692187439, + "narHash": "sha256-m7c4EPFWmB1OmV3dSYQk2qtXR53xOjZdLCjMtzHSK34=", "ref": "main", - "rev": "a51e591b7fdf8881ac0237452691df7b1aceecd3", - "revCount": 10, + "rev": "408f3deab2e2f6ae60349776dde02c44f71fb386", + "revCount": 16, "type": "git", "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git" }, @@ -605,11 +672,11 @@ "pre-commit-hooks": "pre-commit-hooks_6" }, "locked": { - "lastModified": 1681762240, - "narHash": "sha256-+PLx9xHBvV70dA7Gy/+YTH1w3PcSOrGV0z0rGxts8jU=", + "lastModified": 1696619796, + "narHash": "sha256-4PjNRfnk22EuGCu7mF2sAb3JtaWKuBdgew4frd+Xpts=", "ref": "main", - "rev": "a51e591b7fdf8881ac0237452691df7b1aceecd3", - "revCount": 10, + "rev": "8887555c96886d81d671fb68a3a2d000e578c4e0", + "revCount": 19, "type": "git", "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git" }, @@ -640,6 +707,27 @@ "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git" } }, + "hs-flake-utils_8": { + "inputs": { + "flake-utils": "flake-utils_16", + "nixpkgs": "nixpkgs_8", + "pre-commit-hooks": "pre-commit-hooks_8" + }, + "locked": { + "lastModified": 1677773826, + "narHash": "sha256-xJmOtHugr4k2zNhP/AF6JdIUnIEyM+TEspLn2n5kloc=", + "ref": "main", + "rev": "d3a83fdd9563546ca41771186427638e685a2e2b", + "revCount": 9, + "type": "git", + "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git" + }, + "original": { + "ref": "main", + "type": "git", + "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git" + } + }, "nixpkgs": { "locked": { "lastModified": 1677624842, @@ -768,6 +856,22 @@ "type": "github" } }, + "nixpkgs-stable_8": { + "locked": { + "lastModified": 1673800717, + "narHash": "sha256-SFHraUqLSu5cC6IxTprex/nTsI81ZQAtDvlBvGDWfnA=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2f9fd351ec37f5d479556cd48be4ca340da59b8f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-22.11", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs_2": { "locked": { "lastModified": 1677624842, @@ -864,6 +968,22 @@ "type": "github" } }, + "nixpkgs_8": { + "locked": { + "lastModified": 1677624842, + "narHash": "sha256-4DF9DbDuK4/+KYx0L6XcPBeDHUFVCtzok2fWtwXtb5w=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "d70f5cd5c3bef45f7f52698f39e7cc7a89daa7f0", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-22.11", + "repo": "nixpkgs", + "type": "github" + } + }, "pre-commit-hooks": { "inputs": { "flake-compat": "flake-compat", @@ -896,13 +1016,13 @@ "inputs": { "flake-compat": "flake-compat_2", "flake-utils": [ - "tahoe-directory", + "tahoe-chk", "hs-flake-utils", "flake-utils" ], "gitignore": "gitignore_2", "nixpkgs": [ - "tahoe-directory", + "tahoe-chk", "hs-flake-utils", "nixpkgs" ], @@ -927,14 +1047,12 @@ "flake-compat": "flake-compat_3", "flake-utils": [ "tahoe-directory", - "tahoe-capabilities", "hs-flake-utils", "flake-utils" ], "gitignore": "gitignore_3", "nixpkgs": [ "tahoe-directory", - "tahoe-capabilities", "hs-flake-utils", "nixpkgs" ], @@ -959,14 +1077,14 @@ "flake-compat": "flake-compat_4", "flake-utils": [ "tahoe-directory", - "tahoe-chk", + "tahoe-capabilities", "hs-flake-utils", "flake-utils" ], "gitignore": "gitignore_4", "nixpkgs": [ "tahoe-directory", - "tahoe-chk", + "tahoe-capabilities", "hs-flake-utils", "nixpkgs" ], @@ -990,15 +1108,13 @@ "inputs": { "flake-compat": "flake-compat_5", "flake-utils": [ - "tahoe-directory", - "tahoe-ssk", + "tahoe-great-black-swamp", "hs-flake-utils", "flake-utils" ], "gitignore": "gitignore_5", "nixpkgs": [ - "tahoe-directory", - "tahoe-ssk", + "tahoe-great-black-swamp", "hs-flake-utils", "nixpkgs" ], @@ -1022,17 +1138,13 @@ "inputs": { "flake-compat": "flake-compat_6", "flake-utils": [ - "tahoe-directory", "tahoe-ssk", - "tahoe-capabilities", "hs-flake-utils", "flake-utils" ], "gitignore": "gitignore_6", "nixpkgs": [ - "tahoe-directory", "tahoe-ssk", - "tahoe-capabilities", "hs-flake-utils", "nixpkgs" ], @@ -1056,13 +1168,15 @@ "inputs": { "flake-compat": "flake-compat_7", "flake-utils": [ - "tahoe-great-black-swamp", + "tahoe-ssk", + "tahoe-capabilities", "hs-flake-utils", "flake-utils" ], "gitignore": "gitignore_7", "nixpkgs": [ - "tahoe-great-black-swamp", + "tahoe-ssk", + "tahoe-capabilities", "hs-flake-utils", "nixpkgs" ], @@ -1082,6 +1196,38 @@ "type": "github" } }, + "pre-commit-hooks_8": { + "inputs": { + "flake-compat": "flake-compat_8", + "flake-utils": [ + "tahoe-ssk", + "tahoe-chk", + "hs-flake-utils", + "flake-utils" + ], + "gitignore": "gitignore_8", + "nixpkgs": [ + "tahoe-ssk", + "tahoe-chk", + "hs-flake-utils", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable_8" + }, + "locked": { + "lastModified": 1677722096, + "narHash": "sha256-7mjVMvCs9InnrRybBfr5ohqcOz+pyEX8m22C1XsDilg=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "61a3511668891c68ebd19d40122150b98dc2fe3b", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, "root": { "inputs": { "flake-utils": "flake-utils", @@ -1094,16 +1240,10 @@ "tahoe-directory", "tahoe-capabilities" ], - "tahoe-chk": [ - "tahoe-directory", - "tahoe-chk" - ], + "tahoe-chk": "tahoe-chk", "tahoe-directory": "tahoe-directory", "tahoe-great-black-swamp": "tahoe-great-black-swamp", - "tahoe-ssk": [ - "tahoe-directory", - "tahoe-ssk" - ] + "tahoe-ssk": "tahoe-ssk" } }, "systems": { @@ -1138,8 +1278,8 @@ }, "tahoe-capabilities": { "inputs": { - "flake-utils": "flake-utils_5", - "hs-flake-utils": "hs-flake-utils_3", + "flake-utils": "flake-utils_7", + "hs-flake-utils": "hs-flake-utils_4", "nixpkgs": [ "tahoe-directory", "hs-flake-utils", @@ -1163,10 +1303,9 @@ }, "tahoe-capabilities_2": { "inputs": { - "flake-utils": "flake-utils_11", - "hs-flake-utils": "hs-flake-utils_6", + "flake-utils": "flake-utils_13", + "hs-flake-utils": "hs-flake-utils_7", "nixpkgs": [ - "tahoe-directory", "tahoe-ssk", "hs-flake-utils", "nixpkgs" @@ -1188,60 +1327,88 @@ }, "tahoe-chk": { "inputs": { - "flake-utils": "flake-utils_7", - "hs-flake-utils": "hs-flake-utils_4", + "flake-utils": "flake-utils_3", + "hs-flake-utils": "hs-flake-utils_2", "nixpkgs": [ - "tahoe-directory", "hs-flake-utils", "nixpkgs" ] }, "locked": { - "lastModified": 1683552888, - "narHash": "sha256-h9pgP/LYPtUr5CeCAhqt1XJyAqKTnkQxuIygiTulU/U=", - "ref": "refs/tags/0.1.0.1", - "rev": "05aeb5a433b85406ca3c0c313c46299a1026ade0", - "revCount": 344, + "lastModified": 1696262854, + "narHash": "sha256-0/6VEsjXe7EvYY2BnkWkmHCVzdp1WcFLjx5mvHDMLnM=", + "ref": "refs/tags/0.2.0.0", + "rev": "42ae52257ec6e6d8eaa9a56662ca5edfbce8074b", + "revCount": 487, + "type": "git", + "url": "https://whetstone.private.storage/PrivateStorage/tahoe-chk.git" + }, + "original": { + "ref": "refs/tags/0.2.0.0", + "type": "git", + "url": "https://whetstone.private.storage/PrivateStorage/tahoe-chk.git" + } + }, + "tahoe-chk_2": { + "inputs": { + "flake-utils": "flake-utils_15", + "hs-flake-utils": "hs-flake-utils_8", + "nixpkgs": [ + "tahoe-ssk", + "hs-flake-utils", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1696262854, + "narHash": "sha256-0/6VEsjXe7EvYY2BnkWkmHCVzdp1WcFLjx5mvHDMLnM=", + "ref": "refs/tags/0.2.0.0", + "rev": "42ae52257ec6e6d8eaa9a56662ca5edfbce8074b", + "revCount": 487, "type": "git", "url": "https://whetstone.private.storage/PrivateStorage/tahoe-chk" }, "original": { - "ref": "refs/tags/0.1.0.1", + "ref": "refs/tags/0.2.0.0", "type": "git", "url": "https://whetstone.private.storage/PrivateStorage/tahoe-chk" } }, "tahoe-directory": { "inputs": { - "flake-utils": "flake-utils_3", - "hs-flake-utils": "hs-flake-utils_2", + "flake-utils": "flake-utils_5", + "hs-flake-utils": "hs-flake-utils_3", "nixpkgs": [ "hs-flake-utils", "nixpkgs" ], "tahoe-capabilities": "tahoe-capabilities", - "tahoe-chk": "tahoe-chk", - "tahoe-ssk": "tahoe-ssk" + "tahoe-chk": [ + "tahoe-chk" + ], + "tahoe-ssk": [ + "tahoe-ssk" + ] }, "locked": { - "lastModified": 1692283409, - "narHash": "sha256-bEWf+jzyF7FOG1W8INiIzWIyS86ywaYGFFoCoh+1qWI=", - "ref": "refs/tags/0.1.0.0", - "rev": "f57d71df59d9d7fa4f72dfecd3ce39631a05c905", - "revCount": 26, + "lastModified": 1696949877, + "narHash": "sha256-P5g9ouGBj+KiDCIfAPMK9qNLAk32f54jdtMxq0bFI14=", + "ref": "main", + "rev": "ccffb1b8e965ccbea502872677facdfeece9603c", + "revCount": 31, "type": "git", "url": "https://whetstone.private.storage/PrivateStorage/tahoe-directory.git" }, "original": { - "ref": "refs/tags/0.1.0.0", + "ref": "main", "type": "git", "url": "https://whetstone.private.storage/PrivateStorage/tahoe-directory.git" } }, "tahoe-great-black-swamp": { "inputs": { - "flake-utils": "flake-utils_13", - "hs-flake-utils": "hs-flake-utils_7", + "flake-utils": "flake-utils_9", + "hs-flake-utils": "hs-flake-utils_5", "nixpkgs": [ "hs-flake-utils", "nixpkgs" @@ -1251,48 +1418,44 @@ ] }, "locked": { - "lastModified": 1685640961, - "narHash": "sha256-zH9bRWqm1dYcgg9/VSVJ7y8qZIM8fwp5H0rRsaWT8lg=", - "ref": "refs/tags/0.3.0.0", - "rev": "3d00d90d1e64897aa92f33a012343a5ca46fe7fc", - "revCount": 194, + "lastModified": 1696949119, + "narHash": "sha256-DSrpTLdE4tnpLzTrInWAss1fg8CHSIa+sLGtewSO3Io=", + "ref": "refs/tags/0.3.1.0", + "rev": "75aa8fe8ba655bbf7fd5025ef8dc2fed6f2ee703", + "revCount": 243, "type": "git", "url": "https://whetstone.private.storage/PrivateStorage/tahoe-great-black-swamp" }, "original": { - "ref": "refs/tags/0.3.0.0", + "ref": "refs/tags/0.3.1.0", "type": "git", "url": "https://whetstone.private.storage/PrivateStorage/tahoe-great-black-swamp" } }, "tahoe-ssk": { "inputs": { - "flake-utils": "flake-utils_9", - "hs-flake-utils": "hs-flake-utils_5", + "flake-utils": "flake-utils_11", + "hs-flake-utils": "hs-flake-utils_6", "nixpkgs": [ - "tahoe-directory", "hs-flake-utils", "nixpkgs" ], "tahoe-capabilities": "tahoe-capabilities_2", - "tahoe-chk": [ - "tahoe-directory", - "tahoe-chk" - ] + "tahoe-chk": "tahoe-chk_2" }, "locked": { - "lastModified": 1692193506, - "narHash": "sha256-0UDrh4ZcBHU+4yrLfVe+9wkYF4K1QJoecdOI083Gu5w=", - "ref": "refs/tags/0.2.1.0", - "rev": "96941786b56e9fb949d62a14bacd5ed2c81cd7ab", - "revCount": 112, + "lastModified": 1696941203, + "narHash": "sha256-y+Clh8ZZ/sgsPS8BoJUAN0IJyeNsXZu1l7huqFqHc7U=", + "ref": "refs/tags/0.3.0.0", + "rev": "b7fb49307c96e9c508e01982ef19e857deb55fb8", + "revCount": 122, "type": "git", - "url": "https://whetstone.private.storage/PrivateStorage/tahoe-ssk" + "url": "https://whetstone.private.storage/PrivateStorage/tahoe-ssk.git" }, "original": { - "ref": "refs/tags/0.2.1.0", + "ref": "refs/tags/0.3.0.0", "type": "git", - "url": "https://whetstone.private.storage/PrivateStorage/tahoe-ssk" + "url": "https://whetstone.private.storage/PrivateStorage/tahoe-ssk.git" } } }, diff --git a/flake.nix b/flake.nix index 906f465e385912d2d41b42dcd25839467c1e02d3..64374f4776a8c2e97729711ba4bac97d60057aad 100644 --- a/flake.nix +++ b/flake.nix @@ -8,16 +8,25 @@ hs-flake-utils.url = "git+https://whetstone.private.storage/jcalderone/hs-flake-utils.git?ref=main"; tahoe-directory = { - url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-directory.git?ref=refs/tags/0.1.0.0"; + url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-directory.git?ref=main"; inputs.nixpkgs.follows = "hs-flake-utils/nixpkgs"; + inputs.tahoe-chk.follows = "tahoe-chk"; + inputs.tahoe-ssk.follows = "tahoe-ssk"; }; - - tahoe-chk.follows = "tahoe-directory/tahoe-chk"; - tahoe-ssk.follows = "tahoe-directory/tahoe-ssk"; tahoe-capabilities.follows = "tahoe-directory/tahoe-capabilities"; + tahoe-chk = { + url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-chk.git?ref=refs/tags/0.2.0.0"; + inputs.nixpkgs.follows = "hs-flake-utils/nixpkgs"; + }; + + tahoe-ssk = { + url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-ssk.git?ref=refs/tags/0.3.0.0"; + inputs.nixpkgs.follows = "hs-flake-utils/nixpkgs"; + }; + tahoe-great-black-swamp = { - url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-great-black-swamp?ref=refs/tags/0.3.0.0"; + url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-great-black-swamp?ref=refs/tags/0.3.1.0"; inputs.nixpkgs.follows = "hs-flake-utils/nixpkgs"; inputs.tahoe-chk.follows = "tahoe-chk"; }; diff --git a/gbs-downloader.cabal b/gbs-downloader.cabal index 46c02301ab586cc73ff769a434a9d3f73789ebb1..ee59009836230a852db53248c9e5bcaf2cc84042 100644 --- a/gbs-downloader.cabal +++ b/gbs-downloader.cabal @@ -117,13 +117,14 @@ library , http-client >=0.6.4.1 && <0.8 , http-client-tls >=0.3.5.3 && <0.4 , http-types >=0.12.3 && <0.13 + , lens >=4.0 && <5.3 , network-uri >=2.6.3 && <2.7 , servant-client >=0.16.0.1 && <0.21 , servant-client-core >=0.16 && <0.21 - , tahoe-chk >=0.1 && <0.2 + , tahoe-chk >=0.2 && <0.3 , tahoe-directory >=0.1 && <0.2 - , tahoe-great-black-swamp >=0.3 && <0.4 - , tahoe-ssk >=0.2 && <0.3 + , tahoe-great-black-swamp >=0.3.1 && <0.4 + , tahoe-ssk >=0.3 && <0.4 , text >=1.2.3.1 && <1.3 , yaml >=0.11.5.0 && <0.11.9.0 || >=0.11.9.0.0 && <0.12 @@ -156,7 +157,7 @@ executable download-chk , containers >=0.6.0.1 && <0.7 , gbs-downloader , megaparsec >=8.0 && <9.3 - , tahoe-chk >=0.1 && <0.2 + , tahoe-chk >=0.2 && <0.3 , text >=1.2.3.1 && <1.3 , yaml >=0.11.5.0 && <0.11.9.0 || >=0.11.9.0.0 && <0.12 @@ -179,7 +180,7 @@ executable download-sdmf , containers >=0.6.0.1 && <0.7 , gbs-downloader , megaparsec >=8.0 && <9.3 - , tahoe-ssk >=0.2 && <0.3 + , tahoe-ssk >=0.3 && <0.4 , text >=1.2.3.1 && <1.3 , yaml >=0.11.5.0 && <0.11.9.0 || >=0.11.9.0.0 && <0.12 @@ -199,9 +200,9 @@ executable list-dircap , containers >=0.6.0.1 && <0.7 , gbs-downloader , megaparsec >=8.0 && <9.3 - , tahoe-chk >=0.1 && <0.2 + , tahoe-chk >=0.2 && <0.3 , tahoe-directory >=0.1 && <0.2 - , tahoe-ssk >=0.2 && <0.3 + , tahoe-ssk >=0.3 && <0.4 , text >=1.2.3.1 && <1.3 , yaml >=0.11.5.0 && <0.11.9.0 || >=0.11.9.0.0 && <0.12 @@ -246,11 +247,12 @@ test-suite gbs-downloader-test , hedgehog >=1.0.3 && <1.1 , http-client >=0.6.4.1 && <0.8 , http-types >=0.12.3 && <0.13 + , lens >=4.0 && <5.3 , memory >=0.15 && <0.17 , servant-client >=0.16.0.1 && <0.21 , servant-client-core >=0.16 && <0.21 - , tahoe-chk >=0.1 && <0.2 - , tahoe-ssk >=0.2 && <0.3 + , tahoe-chk >=0.2 && <0.3 + , tahoe-ssk >=0.3 && <0.4 , tasty >=1.2.3 && <1.5 , tasty-hedgehog >=1.0.0.2 && <1.2 , tasty-hunit >=0.10.0.2 && <0.11 diff --git a/src/Tahoe/Download/Internal/Capability.hs b/src/Tahoe/Download/Internal/Capability.hs index e0b4c3e573afac1106f4b7226af2f1f1f78a9431..c04f7940353ca2db13ca344bc96e66d1a7d25c42 100644 --- a/src/Tahoe/Download/Internal/Capability.hs +++ b/src/Tahoe/Download/Internal/Capability.hs @@ -3,9 +3,10 @@ module Tahoe.Download.Internal.Capability where import Control.Exception (SomeException, throwIO, try) +import Control.Lens (view) import Control.Monad.IO.Class import Data.Bifunctor (Bifunctor (..)) -import Data.Binary (Word8, decodeOrFail) +import Data.Binary (decodeOrFail) import Data.Binary.Get (ByteOffset) import qualified Data.ByteString.Lazy as LB import Data.Foldable (foldlM) @@ -74,11 +75,11 @@ class Readable r where instance Verifiable CHK.Verifier where type ShareT CHK.Verifier = Tahoe.CHK.Share.Share - getShareNumbers v s = liftIO $ storageServerGetBuckets s (CHK.storageIndex v) - getStorageIndex CHK.Verifier{storageIndex} = storageIndex + getShareNumbers v s = liftIO $ storageServerGetBuckets s (view CHK.storageIndex v) + getStorageIndex = view CHK.storageIndex -- CHK is pure, we don't have to ask the StorageServer - getRequiredTotal CHK.Verifier{required, total} _ = pure $ pure (fromIntegral required, fromIntegral total) + getRequiredTotal verifier _ = pure $ pure (fromIntegral (view CHK.required verifier), fromIntegral (view CHK.total verifier)) deserializeShare _ = fmap (\(_, _, c) -> c) . decodeOrFail @@ -89,13 +90,13 @@ instance Verifiable CHK.Verifier where instance Readable CHK.Reader where type Verifier CHK.Reader = CHK.Verifier - getVerifiable = CHK.verifier + getVerifiable = view CHK.verifier decodeShare r shareList = do cipherText <- liftIO $ Tahoe.CHK.decode r shareList - case cipherText of - Nothing -> pure $ Left ShareDecodingFailed - Just ct -> - pure . Right $ Tahoe.CHK.Encrypt.decrypt (CHK.readKey r) ct + pure $ case cipherText of + Left _ -> Left ShareDecodingFailed + Right ct -> + Right $ Tahoe.CHK.Encrypt.decryptLazy (view CHK.readKey r) ct firstJustsM :: (Monad m, Foldable f) => f (m (Maybe a)) -> m (Maybe a) firstJustsM = foldlM go Nothing @@ -124,7 +125,7 @@ instance Verifiable SDMF.Verifier where where -- Get the Required, Total parameters for one share number, if -- possible. - getParams :: MonadIO m => Word8 -> m (Maybe (Int, Int)) + getParams :: MonadIO m => Int -> m (Maybe (Int, Int)) getParams shareNum = liftIO $ do errorOrShareBytes <- try $ storageServerRead ss storageIndex shareNum case errorOrShareBytes of diff --git a/src/Tahoe/Download/Internal/Client.hs b/src/Tahoe/Download/Internal/Client.hs index 43cc02e6b609319c18f36804146f77d35e005e52..308ebe38127ba4b9e60388bd5a4b102c0c8ad5b7 100644 --- a/src/Tahoe/Download/Internal/Client.hs +++ b/src/Tahoe/Download/Internal/Client.hs @@ -7,66 +7,17 @@ import Control.Exception import Control.Monad.IO.Class import qualified Data.ByteString as B import Data.ByteString.Base32 -import qualified Data.ByteString.Base64 as Base64 import qualified Data.Set as Set import qualified Data.Text as T -import Data.Text.Encoding -import Network.Connection -import Network.HTTP.Client (Manager, ManagerSettings (managerModifyRequest), Request (requestHeaders)) -import Network.HTTP.Client.TLS import Network.HTTP.Types (ByteRange) +import Network.URI (uriToString) import Servant.Client import Tahoe.Announcement import Tahoe.CHK.Server ( StorageServer (..), ) import TahoeLAFS.Storage.API (CBORSet (CBORSet), ShareNumber (ShareNumber)) -import Text.Read (readMaybe) - --- | Make an HTTPS URL. -https :: String -> Int -> BaseUrl -https host port = - BaseUrl - { baseUrlScheme = Https - , baseUrlHost = host - , baseUrlPort = port - , baseUrlPath = "" - } - -{- | Make an HTTPS manager for the given SPKI hash and swissnum. - - The SPKI hash is _not_ used to authenticate the server! See - https://whetstone.private.storage/privatestorage/tahoe-great-black-swamp/-/issues/27 --} -managerSettingsForService :: T.Text -> T.Text -> ManagerSettings -managerSettingsForService _ swissnum = - (mkManagerSettings tlsSettings sockSettings){managerModifyRequest = pure . authorize} - where - tlsSettings = TLSSettingsSimple True True True - sockSettings = Nothing - swissnumBytes = encodeUtf8 swissnum - swissnumBase64 = Base64.encode swissnumBytes - headerCompleteBytes = B.concat ["Tahoe-LAFS ", swissnumBase64] - authorize req = - req - { requestHeaders = - ( "Authorization" - , headerCompleteBytes - ) : - requestHeaders req - } - --- | Make a manager suitable for use with a Great Black Swamp server. -newGBSManager :: - MonadIO m => - [Char] -> - String -> - m Manager -newGBSManager tubid swissnum = - newTlsManagerWith $ - managerSettingsForService - (T.pack . init $ tubid) - (T.pack swissnum) +import TahoeLAFS.Storage.Client (NURL, parseNURL, runGBS) {- | An unrecoverable problem arose while attempting to download and/or read some application data. @@ -138,12 +89,10 @@ type ReadShare = String -> ShareNumber -> Maybe [ByteRange] -> ClientM B.ByteStr {- | Create a StorageServer that will speak Great Black Swamp using the given manager to the server at the given host/port. -} -mkWrapper :: GetShareNumbers -> ReadShare -> Manager -> [Char] -> Int -> StorageServer -mkWrapper getShareNumbers readShare manager host realPort = +mkWrapper :: GetShareNumbers -> ReadShare -> NURL -> StorageServer +mkWrapper getShareNumbers readShare nurl = StorageServer{..} where - baseUrl = https host realPort - env = mkClientEnv manager baseUrl toBase32 = T.unpack . T.toLower . encodeBase32Unpadded storageServerID = undefined @@ -152,7 +101,7 @@ mkWrapper getShareNumbers readShare manager host realPort = storageServerRead storageIndex shareNum = do let clientm = readShare (toBase32 storageIndex) (ShareNumber $ fromIntegral shareNum) Nothing - res <- runClientM clientm env + res <- runGBS nurl clientm case res of Left err -> do throwIO err @@ -160,7 +109,7 @@ mkWrapper getShareNumbers readShare manager host realPort = storageServerGetBuckets storageIndex = do let clientm = getShareNumbers (toBase32 storageIndex) - r <- try $ runClientM clientm env + r <- try $ runGBS nurl clientm case r of Left (_ :: SomeException) -> do pure mempty @@ -174,22 +123,10 @@ mkWrapper getShareNumbers readShare manager host realPort = on the server at the given URI. -} makeServer :: MonadIO m => GetShareNumbers -> ReadShare -> URI -> m (Either LookupError StorageServer) -makeServer - getShareNumbers - readShare - URI - { uriScheme = "pb:" - , uriAuthority = Just URIAuth{uriUserInfo = tubid, uriRegName = host, uriPort = (':' : port)} - , uriPath = ('/' : swissnum) - , uriFragment = "" -- It's a fURL, not a NURL, so there's no fragment. - } = - case readMaybe port of - Nothing -> pure . Left . PortParseError $ port - Just realPort -> do - manager <- liftIO $ newGBSManager tubid swissnum - - pure . Right $ mkWrapper getShareNumbers readShare manager host realPort -makeServer _ _ _ = pure . Left $ AnnouncementStructureUnmatched +makeServer getShareNumbers readShare uri = + pure $ case parseNURL (T.pack $ uriToString id uri "") of + Nothing -> Left AnnouncementStructureUnmatched + Just nurl -> Right $ mkWrapper getShareNumbers readShare nurl announcementToStorageServer :: MonadIO m => GetShareNumbers -> ReadShare -> StorageServerAnnouncement -> m (Either LookupError StorageServer) announcementToStorageServer getShareNumbers readShare ann = diff --git a/test/Spec.hs b/test/Spec.hs index 4a3cb859701570b857dd47574e78a75ca3938c7f..c5ba7736b431e7b185fc5cd529ba8799af27fc4a 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -1,10 +1,14 @@ +{-# LANGUAGE TypeApplications #-} + module Main where import Control.Exception (Exception, throwIO) +import Control.Lens (view) import Control.Monad (replicateM, when) import Control.Monad.IO.Class (liftIO) -import Crypto.Cipher.Types (nullIV) -import Crypto.Classes (buildKey) +import Crypto.Cipher.AES (AES128) +import Crypto.Cipher.Types (Cipher (cipherInit, cipherKeySize), KeySizeSpecifier (KeySizeEnum, KeySizeFixed, KeySizeRange), nullIV) +import Crypto.Error (CryptoFailable (CryptoPassed)) import qualified Crypto.Hash import Data.Bifunctor (bimap) import qualified Data.Binary as Binary @@ -36,8 +40,10 @@ import Tahoe.Announcement ( parseURI', ) import qualified Tahoe.CHK -import Tahoe.CHK.Capability (Reader (..), Verifier (..)) +import Tahoe.CHK.Capability (makeReader, storageIndex, verifier) +import qualified Tahoe.CHK.Capability as CHK import qualified Tahoe.CHK.Encrypt +import Tahoe.CHK.SHA256d (Digest' (Digest')) import Tahoe.CHK.Server (StorageServer (..)) import Tahoe.CHK.Types (Parameters (..)) import Tahoe.CHK.Upload (getConvergentKey) @@ -166,8 +172,8 @@ tests = -- Two shares exist. server <- memoryStorageServer - storageServerWrite server (storageIndex . verifier $ cap) 0 0 "Hello world" - storageServerWrite server (storageIndex . verifier $ cap) 1 0 "Hello world" + storageServerWrite server (view (verifier . storageIndex) cap) 0 0 "Hello world" + storageServerWrite server (view (verifier . storageIndex) cap) 1 0 "Hello world" -- Make the server reachable. let openServer = simpleLookup [("somewhere", server)] @@ -191,7 +197,7 @@ tests = -- Three shares exist somewhere <- memoryStorageServer - let idx = storageIndex . verifier $ cap + let idx = view (verifier . storageIndex) cap offset = 0 storageServerWrite somewhere idx 0 offset "Hello world" storageServerWrite somewhere idx 1 offset "Hello world" @@ -248,20 +254,20 @@ tests = placedShares <- forAll $ Gen.subsequence (zip [0 ..] (Binary.encode <$> shares)) when (null placedShares) discard - let verifier = SDMF.readerVerifier . SDMF.writerReader $ cap - storageIndex = SDMF.Keys.unStorageIndex . SDMF.verifierStorageIndex $ verifier + let verifier' = SDMF.readerVerifier . SDMF.writerReader $ cap + storageIndex' = SDMF.Keys.unStorageIndex . SDMF.verifierStorageIndex $ verifier' -- Be sure to create the server last to avoid having Hedgehog -- re-use it for multiple cases. server <- liftIO memoryStorageServer liftIO $ placeShares - storageIndex + storageIndex' placedShares [length placedShares] [server] - r <- getRequiredTotal verifier server + r <- getRequiredTotal verifier' server diff (Just (fromIntegral paramRequiredShares, fromIntegral paramTotalShares)) (==) r , testCase "IO exceptions from storageServerRead are handled" $ do -- An announcement for our server @@ -274,7 +280,7 @@ tests = let cap = trivialCap 3 13 -- Three shares exist - let idx = storageIndex . verifier $ cap + let idx = view (verifier . storageIndex) cap offset = 0 storageServerWrite server idx 0 offset "Hello world" storageServerWrite server idx 1 offset "Hello world" @@ -324,11 +330,11 @@ tests = -- Encrypt and encode the data into shares. let key = getConvergentKey secret params plaintext - ciphertext = Tahoe.CHK.Encrypt.encrypt key plaintext + ciphertext = Tahoe.CHK.Encrypt.encryptLazy key plaintext (shares, cap) <- liftIO $ Tahoe.CHK.encode key params ciphertext -- Distribute the shares. - liftIO $ placeShares (storageIndex . verifier $ cap) (zip [0 ..] (Binary.encode <$> shares)) perServerShareCount servers + liftIO $ placeShares (view (verifier . storageIndex) cap) (zip [0 ..] (Binary.encode <$> shares)) perServerShareCount servers let serverMap = Map.fromList $ zip (Set.toList serverIDs') servers lookupServer = someServers serverMap @@ -369,10 +375,10 @@ tests = annotateShow ciphertext annotateShow iv (shares, writeCap) <- liftIO $ SDMF.encode keypair iv sequenceNumber required total ciphertext - let storageIndex = SDMF.Keys.unStorageIndex . SDMF.verifierStorageIndex . SDMF.readerVerifier . SDMF.writerReader $ writeCap + let storageIndex' = SDMF.Keys.unStorageIndex . SDMF.verifierStorageIndex . SDMF.readerVerifier . SDMF.writerReader $ writeCap readCap = SDMF.writerReader writeCap -- Distribute the shares. - liftIO $ placeShares storageIndex (zip [0 ..] (Binary.encode <$> shares)) perServerShareCount servers + liftIO $ placeShares storageIndex' (zip [0 ..] (Binary.encode <$> shares)) perServerShareCount servers let serverMap = Map.fromList $ zip (Set.toList serverIDs') servers lookupServer = someServers serverMap @@ -462,20 +468,24 @@ tests = v <- Gen.int (Range.linear 0 t) (v :) <$> genListWithSum (maxLength - 1) (t - v) -trivialCap :: Word16 -> Word16 -> Reader -trivialCap required total = Reader{..} +trivialCap :: Word16 -> Word16 -> CHK.Reader +trivialCap required total = makeReader readKey storageIndex' required total size where - Just readKey = buildKey $ B.replicate 32 0x00 - storageIndex = B.replicate 32 0x00 - fingerprint = B.replicate 32 0x00 + keySize = case cipherKeySize @AES128 undefined of + KeySizeRange sz _ -> sz + KeySizeEnum [] -> error "Empty KeySizeEnum" + KeySizeEnum (sz : _) -> sz + KeySizeFixed sz -> sz + + CryptoPassed readKey = cipherInit $ B.replicate keySize 0x00 + storageIndex' = B.replicate 32 0x00 size = 1234 - verifier = Verifier{..} trivialSDMFVerifier :: SDMF.Verifier trivialSDMFVerifier = SDMF.Verifier{..} where verifierStorageIndex = SDMF.Keys.StorageIndex $ B.pack [0 .. 15] - verifierVerificationKeyHash = Crypto.Hash.hash $ B.pack [0 .. 31] + verifierVerificationKeyHash = Digest' . Crypto.Hash.hash . B.pack $ [0 .. 31] -- | A real 404 response from tahoe-great-black-swamp 0.3.0.0. failure404 :: ClientError