From c9211122e65db16b6824888c2da51b0c17e90ca9 Mon Sep 17 00:00:00 2001
From: Jean-Paul Calderone <exarkun@twistedmatrix.com>
Date: Wed, 7 Jun 2023 15:52:45 -0400
Subject: [PATCH] parse the other SDMF directory capability types

And switch to tahoe-capabilities' ConfidentialShowable for better dependency
directions / code sharing
---
 flake.nix                                  | 11 +++--
 nix/haskell-packages.nix                   |  8 ----
 src/Tahoe/Directory.hs                     |  3 +-
 src/Tahoe/Directory/Internal/Capability.hs | 49 +++++++++++++++++-----
 tahoe-directory.cabal                      |  4 +-
 test/Spec.hs                               | 28 ++++++++++---
 6 files changed, 74 insertions(+), 29 deletions(-)
 delete mode 100644 nix/haskell-packages.nix

diff --git a/flake.nix b/flake.nix
index 7b064e5..9d8f32f 100644
--- a/flake.nix
+++ b/flake.nix
@@ -10,12 +10,15 @@
       url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-chk?ref=refs/tags/0.1.0.1";
       inputs.nixpkgs.follows = "hs-flake-utils/nixpkgs";
     };
-
     tahoe-ssk = {
-      url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-ssk?ref=refs/tags/0.2.0.0";
+      url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-ssk.git";
       inputs.nixpkgs.follows = "hs-flake-utils/nixpkgs";
       inputs.tahoe-chk.follows = "tahoe-chk";
     };
+    tahoe-capabilities = {
+      url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-capabilities";
+      inputs.nixpkgs.follows = "hs-flake-utils/nixpkgs";
+    };
   };
 
   outputs = {
@@ -25,6 +28,7 @@
     hs-flake-utils,
     tahoe-chk,
     tahoe-ssk,
+    tahoe-capabilities,
   }: let
     ulib = flake-utils.lib;
     ghcVersion = "ghc8107";
@@ -39,9 +43,10 @@
         src = ./.;
         compilerVersion = ghcVersion;
         packageName = "tahoe-directory";
-        hsPkgsOverrides = import ./nix/haskell-packages.nix {
+        hsPkgsOverrides = hfinal: hprev: {
           tahoe-chk = tahoe-chk.outputs.packages.${system}.default;
           tahoe-ssk = tahoe-ssk.outputs.packages.${system}.default;
+          tahoe-capabilities = tahoe-capabilities.outputs.packages.${system}.default;
           haskellLib = pkgs.haskell.lib;
         };
       };
diff --git a/nix/haskell-packages.nix b/nix/haskell-packages.nix
deleted file mode 100644
index 54848e9..0000000
--- a/nix/haskell-packages.nix
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  haskellLib,
-  tahoe-chk,
-  tahoe-ssk,
-}: hfinal: hprev: {
-  inherit tahoe-chk;
-  inherit tahoe-ssk;
-}
diff --git a/src/Tahoe/Directory.hs b/src/Tahoe/Directory.hs
index 27451c2..dbde173 100644
--- a/src/Tahoe/Directory.hs
+++ b/src/Tahoe/Directory.hs
@@ -5,11 +5,12 @@ module Tahoe.Directory (
 ) where
 
 import Tahoe.Directory.Internal.Capability (
-    ConfidentialShowable (..),
     DirectoryCapability (..),
     pReadCHK,
     pReadSDMF,
     pVerifyCHK,
+    pVerifySDMF,
+    pWriteSDMF,
  )
 import Tahoe.Directory.Internal.Parsing (parse, serialize)
 import Tahoe.Directory.Internal.Types (Directory (..), Entry (..))
diff --git a/src/Tahoe/Directory/Internal/Capability.hs b/src/Tahoe/Directory/Internal/Capability.hs
index 87737f1..756a367 100644
--- a/src/Tahoe/Directory/Internal/Capability.hs
+++ b/src/Tahoe/Directory/Internal/Capability.hs
@@ -5,19 +5,11 @@ module Tahoe.Directory.Internal.Capability where
 import qualified Data.Text as T
 import Data.Void (Void)
 import qualified Tahoe.CHK.Capability as CHK
+import Tahoe.Capability (ConfidentialShowable (..))
 import qualified Tahoe.SDMF as SDMF
 
 import Text.Megaparsec (Parsec, getInput, setInput)
 
-{- | Something which contains confidential information and can be rendered as
- text such that the text also includes confidential information.  It is
- expected (but not required) that such types will also have a Show instance
- which obscures the confidential information.
--}
-class ConfidentialShowable s where
-    -- | Show the value, including any confidential information.
-    confidentiallyShow :: s -> T.Text
-
 {- | A wrapper around some other capability type which signals that the
  plaintext is an encoded list of files.
 -}
@@ -31,9 +23,21 @@ instance ConfidentialShowable (DirectoryCapability CHK.Reader) where
     confidentiallyShow (DirectoryCapability a) =
         T.replace "URI:CHK:" "URI:DIR2-CHK:" (CHK.dangerRealShow (CHK.CHKReader a))
 
+instance ConfidentialShowable (DirectoryCapability SDMF.Verifier) where
+    confidentiallyShow (DirectoryCapability a) =
+        T.replace "URI:SSK-Verifier:" "URI:DIR2-Verifier:" (confidentiallyShow a)
+
+instance ConfidentialShowable (DirectoryCapability SDMF.Reader) where
+    confidentiallyShow (DirectoryCapability a) =
+        T.replace "URI:SSK-RO:" "URI:DIR2-RO:" (confidentiallyShow a)
+
+instance ConfidentialShowable (DirectoryCapability SDMF.Writer) where
+    confidentiallyShow (DirectoryCapability a) =
+        T.replace "URI:SSK:" "URI:DIR2:" (confidentiallyShow a)
+
 type Parser = Parsec Void T.Text
 
-{- | Parse a CHK verifier directory capability.
+{- | Parse a CHK directory verifier capability.
 
  The implementation is a cheesy hack that does string substitution on the
  input before applying the original CHK verifier parser.
@@ -45,7 +49,7 @@ pVerifyCHK = do
     v <- CHK.pVerifier
     pure $ DirectoryCapability v
 
-{- | Parse a CHK reader directory capability.
+{- | Parse a CHK directory reader capability.
 
  The implementation is a cheesy hack that does string substitution on the
  input before applying the original CHK reader parser.
@@ -57,9 +61,32 @@ pReadCHK = do
     v <- CHK.pReader
     pure $ DirectoryCapability v
 
+{- | Parse an SDMF directory verifier capability.  As is the case for the other
+ directory capability parsers, the implementation is cheesy.
+-}
+pVerifySDMF :: Parser (DirectoryCapability SDMF.Verifier)
+pVerifySDMF = do
+    s <- getInput
+    setInput $ T.replace "URI:DIR2-Verifier:" "URI:SSK-Verifier:" s
+    v <- SDMF.pVerifier
+    pure $ DirectoryCapability v
+
+{- | Parse an SDMF directory reader capability.  As is the case for the other
+ directory capability parsers, the implementation is cheesy.
+-}
 pReadSDMF :: Parser (DirectoryCapability SDMF.Reader)
 pReadSDMF = do
     s <- getInput
     setInput $ T.replace "URI:DIR2-RO:" "URI:SSK-RO:" s
     v <- SDMF.pReader
     pure $ DirectoryCapability v
+
+{- | Parse an SDMF directory writer capability.  As is the case for the other
+ directory capability parsers, the implementation is cheesy.
+-}
+pWriteSDMF :: Parser (DirectoryCapability SDMF.Writer)
+pWriteSDMF = do
+    s <- getInput
+    setInput $ T.replace "URI:DIR2:" "URI:SSK:" s
+    v <- SDMF.pWriter
+    pure $ DirectoryCapability v
diff --git a/tahoe-directory.cabal b/tahoe-directory.cabal
index 066745f..de8c35b 100644
--- a/tahoe-directory.cabal
+++ b/tahoe-directory.cabal
@@ -95,9 +95,10 @@ library
     Tahoe.Directory.Internal.Types
 
   build-depends:
-    , base        >=4 && <5.0
+    , base                >=4 && <5.0
     , bytestring
     , megaparsec
+    , tahoe-capabilities
     , tahoe-chk
     , tahoe-ssk
     , text
@@ -135,6 +136,7 @@ test-suite tahoe-directory-test
     , bytestring
     , hedgehog
     , megaparsec
+    , tahoe-capabilities
     , tahoe-directory
     , tasty
     , tasty-hedgehog
diff --git a/test/Spec.hs b/test/Spec.hs
index 5bb0aa0..5caab95 100644
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -4,8 +4,8 @@ import qualified Data.ByteString as B
 import Generators (directories)
 import Hedgehog (forAll, property, tripping)
 import System.IO (hSetEncoding, stderr, stdout, utf8)
+import Tahoe.Capability (confidentiallyShow)
 import qualified Tahoe.Directory as Directory
-import Tahoe.Directory.Internal.Capability (ConfidentialShowable (confidentiallyShow), pReadCHK, pVerifyCHK)
 import Test.Tasty (TestTree, defaultMain, testGroup)
 import Test.Tasty.HUnit (assertEqual, testCase)
 import Test.Tasty.Hedgehog (testProperty)
@@ -25,18 +25,36 @@ tests =
             property $ do
                 directory <- forAll directories
                 tripping directory Directory.serialize Directory.parse
-        , testCase "well-known directory CHK read capability round-trip through parseCapability . confidentiallyShow" $ do
+        , testCase "well-known directory CHK read capability round-trips through parseCapability . confidentiallyShow" $ do
             -- ❯ curl -XPOST http://localhost:3456/uri?t=mkdir-immutable --data '{"foo": ["filenode", {}], "bar": ["filenode", {}], "baz": ["filenode", {}]}'
             let original = "URI:DIR2-CHK:46y5edbbxojwg5ez4lelafu5jy:fbgn7ijfxarstdxmr363et4de522n7eslnqxavymfqkoax4lc65q:3:10:63"
-            let parsed = parse pReadCHK "" original
+            let parsed = parse Directory.pReadCHK "" original
             let serialized = confidentiallyShow <$> parsed
             assertEqual "original /= serialized" (Right original) serialized
-        , testCase "well-known directory CHK verify capability round-trip through parseCapability . confidentiallyShow" $ do
+        , testCase "well-known directory CHK verify capability round-trips through parseCapability . confidentiallyShow" $ do
             -- `tahoe ls --json <read cap>` to produce verifier
             let original = "URI:DIR2-CHK-Verifier:ni4pjcqflws33ikhifsxqwvmya:fbgn7ijfxarstdxmr363et4de522n7eslnqxavymfqkoax4lc65q:3:10:63"
-            let parsed = parse pVerifyCHK "" original
+            let parsed = parse Directory.pVerifyCHK "" original
             let serialized = confidentiallyShow <$> parsed
             assertEqual "original /= serialized" (Right original) serialized
+        , testCase "well-known directory SDMF write capability round-trips through parseCapability . confidentiallyShow" $ do
+            -- `tahoe mkdir` to produce directory writer
+            let original = "URI:DIR2:ez2k3glrx46svivnnrmh77uieq:c43fbv5274wmphdykpmpweq4moat5co53fvf42lg2z2xekkghm6a"
+                parsed = parse Directory.pWriteSDMF "" original
+                serialized = confidentiallyShow <$> parsed
+            assertEqual "original /= serialized" (Right original) serialized
+        , testCase "well-known directory SDMF read capability round-trips through parseCapability . confidentiallyShow" $ do
+            -- `tahoe ls --json <write cap>` to produce reader
+            let original = "URI:DIR2-RO:g3vdy2tlmpejr2tts7n6pyxbnu:c43fbv5274wmphdykpmpweq4moat5co53fvf42lg2z2xekkghm6a"
+                parsed = parse Directory.pReadSDMF "" original
+                serialized = confidentiallyShow <$> parsed
+            assertEqual "original /= serialized" (Right original) serialized
+        , testCase "well-known directory SDMF verify capability round-trips through parseCapability . confidentiallyShow" $ do
+            -- `tahoe ls --json <write cap>` to produce verifier
+            let original = "URI:DIR2-Verifier:aofaktmdrgegdvnq3vsxnccc7q:c43fbv5274wmphdykpmpweq4moat5co53fvf42lg2z2xekkghm6a"
+                parsed = parse Directory.pVerifySDMF "" original
+                serialized = confidentiallyShow <$> parsed
+            assertEqual "original /= serialized" (Right original) serialized
         ]
 
 main :: IO ()
-- 
GitLab