diff --git a/lib/wallet/api/http/Cardano/Wallet/Api/Http/Server/Error.hs b/lib/wallet/api/http/Cardano/Wallet/Api/Http/Server/Error.hs index a3e39aed9a2..16e1578f6c5 100644 --- a/lib/wallet/api/http/Cardano/Wallet/Api/Http/Server/Error.hs +++ b/lib/wallet/api/http/Cardano/Wallet/Api/Http/Server/Error.hs @@ -515,6 +515,11 @@ instance IsServerError ErrConstructTx where , "The exact error is: " , T.pack (show cryptoError) ] + ErrConstructTxIncorrectRawMetadata -> + apiError err403 InvalidMetadataEncryption $ mconcat + [ "It looks like the metadata to be encrypted does not " + , "have `msg` field which value is to be encrypted." + ] instance IsServerError ErrGetPolicyId where diff --git a/lib/wallet/api/http/Cardano/Wallet/Api/Http/Shelley/Server.hs b/lib/wallet/api/http/Cardano/Wallet/Api/Http/Shelley/Server.hs index 6cfeda6b3d0..f49c51ba757 100644 --- a/lib/wallet/api/http/Cardano/Wallet/Api/Http/Shelley/Server.hs +++ b/lib/wallet/api/http/Cardano/Wallet/Api/Http/Shelley/Server.hs @@ -938,6 +938,8 @@ import qualified Network.Ntp as Ntp import qualified Network.Wai.Handler.Warp as Warp import qualified Network.Wai.Handler.WarpTLS as Warp +import qualified Debug.Trace as TR + -- | Allow configuring which port the wallet server listen to in an integration -- setup. Crashes if the variable is not a number. walletListenFromEnv :: Show e @@ -3087,24 +3089,56 @@ encryptionNonce :: ByteString encryptionNonce = "encrypt-data" -- When encryption is enabled we do the following: --- (a) toJSON on metadata, --- (b) encrypt it --- (c) and create new tx metadata --- (0, TxMetaBytes chunk1) --- (1, TxMetaBytes chunk2) --- .... --- (N, TxMetaBytes chunkN) --- until encrypted metadata is accommodated +-- (a) find field `msg` +-- (b) encrypt its value if present, otherwise emit error +-- (c) and update value of `msg` with the encrypted initial value encoded in base64 +-- [TxMetaText base64_1, TxMetaText base64_2, ..., TxMetaText base64_n] +-- (d) add `enc` field with encryption method value ("base" or "chachapoly1305") toMetadataEncrypted :: ApiEncryptMetadata -> TxMetadataWithSchema -> Either ErrConstructTx Cardano.TxMetadata toMetadataEncrypted apiEncrypt payload = do + msgValue <- findMsgValue encrypted <- encrypt . toBytes $ payload - pure $ toMetadata encrypted + TR.trace ("msgValue: "<> show msgValue<>"\nfindMsgValue1: "<> show findMsgValue1) $ pure $ toMetadata encrypted where ((secretKey,iv), encMethod) = unwrapApiMetadata apiEncrypt + getMsgValue (Cardano.TxMetaText metaField, metaValue) = + if metaField == "msg" then + Just metaValue + else Nothing + getMsgValue _ = Nothing + join Nothing (Just val) = Just val + join (Just val) Nothing = Just val + join Nothing Nothing = Nothing + join (Just val1) (Just val2) = error "only one 'msg' field expected" + -- assumption: `msg` is not embedded beyond first level + -- we could change that in the future + inspectMetaPair (Cardano.TxMetaMap pairs) = + foldl join Nothing (getMsgValue <$> pairs) + inspectMetaPair _ = Nothing + mapMetaPair val Nothing = val + mapMetaPair _ (Just val) = + Cardano.TxMetaBytes $ + BL.toStrict $ + Aeson.encode $ + Cardano.metadataValueToJsonNoSchema val + adjustVals val = + let temp = inspectMetaPair val + in mapMetaPair val temp + findMsgValue = + let (Cardano.TxMetadata themap) = payload ^. #txMetadataWithSchema_metadata + filteredMap = Map.filter (isJust . inspectMetaPair) themap + in if Map.size filteredMap == 1 then + Right $ Map.toList filteredMap + else + Left ErrConstructTxIncorrectRawMetadata + findMsgValue1 = + let (Cardano.TxMetadata themap) = payload ^. #txMetadataWithSchema_metadata + in Map.map adjustVals themap + toBytes = BL.toStrict . Aeson.encode encrypt = case encMethod of diff --git a/lib/wallet/integration/src/Test/Integration/Scenario/API/Shelley/TransactionsNew.hs b/lib/wallet/integration/src/Test/Integration/Scenario/API/Shelley/TransactionsNew.hs index 00c01a063dc..aad36658b39 100644 --- a/lib/wallet/integration/src/Test/Integration/Scenario/API/Shelley/TransactionsNew.hs +++ b/lib/wallet/integration/src/Test/Integration/Scenario/API/Shelley/TransactionsNew.hs @@ -104,6 +104,7 @@ import Cardano.Wallet.Api.Types , ApiWallet , ApiWalletInput (..) , ApiWalletOutput (..) + , EncryptMetadataMethod (..) , ResourceContext (..) , WalletStyle (..) , fromApiEra @@ -518,7 +519,12 @@ spec = describe "NEW_SHELLEY_TRANSACTIONS" $ do it "TRANS_NEW_CREATE_02c - Small metadata encrypted" $ \ctx -> runResourceT $ do - let metadataRaw = TxMetadata (Map.fromList [(1,TxMetaText "hello")]) + let metadataRaw = + TxMetadata (Map.fromList + [ (0,TxMetaText "hello") + , (1,TxMetaMap [(TxMetaText "msg", TxMetaText "hello")]) + , (50, TxMetaNumber 1245) + ]) checkMetadataEncrytion ctx metadataRaw it "TRANS_NEW_CREATE_02d - Big metadata encrypted" $ @@ -5248,7 +5254,7 @@ spec = describe "NEW_SHELLEY_TRANSACTIONS" $ do let metadataToBeEncrypted = TxMetadataWithSchema TxMetadataNoSchema metadataRaw let encryptMetadata = - ApiEncryptMetadata (ApiT $ Passphrase "metadata-secret") Nothing + ApiEncryptMetadata (ApiT $ Passphrase "metadata-secret") (Just ChaChaPoly1305) let payload = Json [json|{ "encrypt_metadata": #{toJSON encryptMetadata}, "metadata": #{toJSON metadataToBeEncrypted} diff --git a/lib/wallet/src/Cardano/Wallet.hs b/lib/wallet/src/Cardano/Wallet.hs index a1a5988bc8c..5102d632738 100644 --- a/lib/wallet/src/Cardano/Wallet.hs +++ b/lib/wallet/src/Cardano/Wallet.hs @@ -3547,6 +3547,7 @@ data ErrConstructTx | ErrConstructTxSharedWalletIncomplete | ErrConstructTxDelegationInvalid | ErrConstructTxEncryptMetadata CryptoError + | ErrConstructTxIncorrectRawMetadata | ErrConstructTxNotImplemented deriving (Show, Eq)