magic-wormhole 0.1.0 → 0.2.0
raw patch · 11 files changed
+316/−182 lines, 11 filesdep ~basedep ~spake2dep ~websocketssetup-changednew-uploaderPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, spake2, websockets
API changes (from Hackage documentation)
- MagicWormhole: newtype Offer
- MagicWormhole.Internal.FileTransfer: newtype Offer
+ MagicWormhole: Directory :: DirectoryMode -> Text -> Natural -> Natural -> Natural -> Offer
+ MagicWormhole: File :: FilePath -> FileOffset -> Offer
+ MagicWormhole: ZipFileDeflated :: DirectoryMode
+ MagicWormhole: [dirName] :: Offer -> Text
+ MagicWormhole: [directoryMode] :: Offer -> DirectoryMode
+ MagicWormhole: [numBytes] :: Offer -> Natural
+ MagicWormhole: [numFiles] :: Offer -> Natural
+ MagicWormhole: [zipSize] :: Offer -> Natural
+ MagicWormhole: data DirectoryMode
+ MagicWormhole: data Offer
+ MagicWormhole: deriveKey :: EncryptedConnection -> Purpose -> Key
+ MagicWormhole.Internal.FileTransfer: Directory :: DirectoryMode -> Text -> Natural -> Natural -> Natural -> Offer
+ MagicWormhole.Internal.FileTransfer: File :: FilePath -> FileOffset -> Offer
+ MagicWormhole.Internal.FileTransfer: ZipFileDeflated :: DirectoryMode
+ MagicWormhole.Internal.FileTransfer: [dirName] :: Offer -> Text
+ MagicWormhole.Internal.FileTransfer: [directoryMode] :: Offer -> DirectoryMode
+ MagicWormhole.Internal.FileTransfer: [numBytes] :: Offer -> Natural
+ MagicWormhole.Internal.FileTransfer: [numFiles] :: Offer -> Natural
+ MagicWormhole.Internal.FileTransfer: [zipSize] :: Offer -> Natural
+ MagicWormhole.Internal.FileTransfer: data DirectoryMode
+ MagicWormhole.Internal.FileTransfer: data Offer
+ MagicWormhole.Internal.FileTransfer: instance Data.Aeson.Types.FromJSON.FromJSON MagicWormhole.Internal.FileTransfer.DirectoryMode
+ MagicWormhole.Internal.FileTransfer: instance Data.Aeson.Types.ToJSON.ToJSON MagicWormhole.Internal.FileTransfer.DirectoryMode
+ MagicWormhole.Internal.FileTransfer: instance GHC.Classes.Eq MagicWormhole.Internal.FileTransfer.DirectoryMode
+ MagicWormhole.Internal.FileTransfer: instance GHC.Show.Show MagicWormhole.Internal.FileTransfer.DirectoryMode
+ MagicWormhole.Internal.Peer: deriveKey :: EncryptedConnection -> Purpose -> Key
Files
- CHANGELOG.md +0/−7
- LICENSE +174/−135
- Setup.hs +2/−0
- cmd/HocusPocus.hs +5/−1
- magic-wormhole.cabal +36/−35
- src/MagicWormhole.hs +2/−0
- src/MagicWormhole/Internal/FileTransfer.hs +46/−3
- src/MagicWormhole/Internal/Peer.hs +9/−1
- tests/FileTransfer.hs +18/−0
- tests/Generator.hs +22/−0
- tests/Tasty.hs +2/−0
− CHANGELOG.md
@@ -1,7 +0,0 @@-# Changelog--## 0.1.0 (2018-01-17)--Initial release--* Exchange text messages with Magic Wormhole peers
LICENSE view
@@ -1,163 +1,202 @@-Apache License -Version 2.0, January 2004+ Apache License+ Version 2.0, January 2004+ http://www.apache.org/licenses/ -http://www.apache.org/licenses/+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION+ 1. Definitions. -1. Definitions.+ "License" shall mean the terms and conditions for use, reproduction,+ and distribution as defined by Sections 1 through 9 of this document. -"License" shall mean the terms and conditions for use, reproduction, and-distribution as defined by Sections 1 through 9 of this document.+ "Licensor" shall mean the copyright owner or entity authorized by+ the copyright owner that is granting the License. -"Licensor" shall mean the copyright owner or entity authorized by the-copyright owner that is granting the License.+ "Legal Entity" shall mean the union of the acting entity and all+ other entities that control, are controlled by, or are under common+ control with that entity. For the purposes of this definition,+ "control" means (i) the power, direct or indirect, to cause the+ direction or management of such entity, whether by contract or+ otherwise, or (ii) ownership of fifty percent (50%) or more of the+ outstanding shares, or (iii) beneficial ownership of such entity. -"Legal Entity" shall mean the union of the acting entity and all other-entities that control, are controlled by, or are under common control with-that entity. For the purposes of this definition, "control" means (i) the-power, direct or indirect, to cause the direction or management of such-entity, whether by contract or otherwise, or (ii) ownership of fifty percent-(50%) or more of the outstanding shares, or (iii) beneficial ownership of such-entity.+ "You" (or "Your") shall mean an individual or Legal Entity+ exercising permissions granted by this License. -"You" (or "Your") shall mean an individual or Legal Entity exercising-permissions granted by this License.+ "Source" form shall mean the preferred form for making modifications,+ including but not limited to software source code, documentation+ source, and configuration files. -"Source" form shall mean the preferred form for making modifications,-including but not limited to software source code, documentation source, and-configuration files.+ "Object" form shall mean any form resulting from mechanical+ transformation or translation of a Source form, including but+ not limited to compiled object code, generated documentation,+ and conversions to other media types. -"Object" form shall mean any form resulting from mechanical transformation or-translation of a Source form, including but not limited to compiled object-code, generated documentation, and conversions to other media types.+ "Work" shall mean the work of authorship, whether in Source or+ Object form, made available under the License, as indicated by a+ copyright notice that is included in or attached to the work+ (an example is provided in the Appendix below). -"Work" shall mean the work of authorship, whether in Source or Object form,-made available under the License, as indicated by a copyright notice that is-included in or attached to the work (an example is provided in the Appendix-below).+ "Derivative Works" shall mean any work, whether in Source or Object+ form, that is based on (or derived from) the Work and for which the+ editorial revisions, annotations, elaborations, or other modifications+ represent, as a whole, an original work of authorship. For the purposes+ of this License, Derivative Works shall not include works that remain+ separable from, or merely link (or bind by name) to the interfaces of,+ the Work and Derivative Works thereof. -"Derivative Works" shall mean any work, whether in Source or Object form, that-is based on (or derived from) the Work and for which the editorial revisions,-annotations, elaborations, or other modifications represent, as a whole, an-original work of authorship. For the purposes of this License, Derivative-Works shall not include works that remain separable from, or merely link (or-bind by name) to the interfaces of, the Work and Derivative Works thereof.+ "Contribution" shall mean any work of authorship, including+ the original version of the Work and any modifications or additions+ to that Work or Derivative Works thereof, that is intentionally+ submitted to Licensor for inclusion in the Work by the copyright owner+ or by an individual or Legal Entity authorized to submit on behalf of+ the copyright owner. For the purposes of this definition, "submitted"+ means any form of electronic, verbal, or written communication sent+ to the Licensor or its representatives, including but not limited to+ communication on electronic mailing lists, source code control systems,+ and issue tracking systems that are managed by, or on behalf of, the+ Licensor for the purpose of discussing and improving the Work, but+ excluding communication that is conspicuously marked or otherwise+ designated in writing by the copyright owner as "Not a Contribution." -"Contribution" shall mean any work of authorship, including the original-version of the Work and any modifications or additions to that Work or-Derivative Works thereof, that is intentionally submitted to Licensor for-inclusion in the Work by the copyright owner or by an individual or Legal-Entity authorized to submit on behalf of the copyright owner. For the purposes-of this definition, "submitted" means any form of electronic, verbal, or-written communication sent to the Licensor or its representatives, including-but not limited to communication on electronic mailing lists, source code-control systems, and issue tracking systems that are managed by, or on behalf-of, the Licensor for the purpose of discussing and improving the Work, but-excluding communication that is conspicuously marked or otherwise designated-in writing by the copyright owner as "Not a Contribution."+ "Contributor" shall mean Licensor and any individual or Legal Entity+ on behalf of whom a Contribution has been received by Licensor and+ subsequently incorporated within the Work. -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf-of whom a Contribution has been received by Licensor and subsequently-incorporated within the Work.+ 2. Grant of Copyright License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ copyright license to reproduce, prepare Derivative Works of,+ publicly display, publicly perform, sublicense, and distribute the+ Work and such Derivative Works in Source or Object form. -2. Grant of Copyright License. Subject to the terms and conditions of this-License, each Contributor hereby grants to You a perpetual, worldwide,-non-exclusive, no-charge, royalty-free, irrevocable copyright license to-reproduce, prepare Derivative Works of, publicly display, publicly perform,-sublicense, and distribute the Work and such Derivative Works in Source or-Object form.+ 3. Grant of Patent License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ (except as stated in this section) patent license to make, have made,+ use, offer to sell, sell, import, and otherwise transfer the Work,+ where such license applies only to those patent claims licensable+ by such Contributor that are necessarily infringed by their+ Contribution(s) alone or by combination of their Contribution(s)+ with the Work to which such Contribution(s) was submitted. If You+ institute patent litigation against any entity (including a+ cross-claim or counterclaim in a lawsuit) alleging that the Work+ or a Contribution incorporated within the Work constitutes direct+ or contributory patent infringement, then any patent licenses+ granted to You under this License for that Work shall terminate+ as of the date such litigation is filed. -3. Grant of Patent License. Subject to the terms and conditions of this-License, each Contributor hereby grants to You a perpetual, worldwide,-non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this-section) patent license to make, have made, use, offer to sell, sell, import,-and otherwise transfer the Work, where such license applies only to those-patent claims licensable by such Contributor that are necessarily infringed by-their Contribution(s) alone or by combination of their Contribution(s) with-the Work to which such Contribution(s) was submitted. If You institute patent-litigation against any entity (including a cross-claim or counterclaim in a-lawsuit) alleging that the Work or a Contribution incorporated within the Work-constitutes direct or contributory patent infringement, then any patent-licenses granted to You under this License for that Work shall terminate as of-the date such litigation is filed.+ 4. Redistribution. You may reproduce and distribute copies of the+ Work or Derivative Works thereof in any medium, with or without+ modifications, and in Source or Object form, provided that You+ meet the following conditions: -4. Redistribution. You may reproduce and distribute copies of the Work or-Derivative Works thereof in any medium, with or without modifications, and in-Source or Object form, provided that You meet the following conditions:+ (a) You must give any other recipients of the Work or+ Derivative Works a copy of this License; and -You must give any other recipients of the Work or Derivative Works a copy of-this License; and+ (b) You must cause any modified files to carry prominent notices+ stating that You changed the files; and -You must cause any modified files to carry prominent notices stating that You-changed the files; and+ (c) You must retain, in the Source form of any Derivative Works+ that You distribute, all copyright, patent, trademark, and+ attribution notices from the Source form of the Work,+ excluding those notices that do not pertain to any part of+ the Derivative Works; and -You must retain, in the Source form of any Derivative Works that You-distribute, all copyright, patent, trademark, and attribution notices from the-Source form of the Work, excluding those notices that do not pertain to any-part of the Derivative Works; and+ (d) If the Work includes a "NOTICE" text file as part of its+ distribution, then any Derivative Works that You distribute must+ include a readable copy of the attribution notices contained+ within such NOTICE file, excluding those notices that do not+ pertain to any part of the Derivative Works, in at least one+ of the following places: within a NOTICE text file distributed+ as part of the Derivative Works; within the Source form or+ documentation, if provided along with the Derivative Works; or,+ within a display generated by the Derivative Works, if and+ wherever such third-party notices normally appear. The contents+ of the NOTICE file are for informational purposes only and+ do not modify the License. You may add Your own attribution+ notices within Derivative Works that You distribute, alongside+ or as an addendum to the NOTICE text from the Work, provided+ that such additional attribution notices cannot be construed+ as modifying the License. -If the Work includes a "NOTICE" text file as part of its distribution, then-any Derivative Works that You distribute must include a readable copy of the-attribution notices contained within such NOTICE file, excluding those notices-that do not pertain to any part of the Derivative Works, in at least one of-the following places: within a NOTICE text file distributed as part of the-Derivative Works; within the Source form or documentation, if provided along-with the Derivative Works; or, within a display generated by the Derivative-Works, if and wherever such third-party notices normally appear. The contents-of the NOTICE file are for informational purposes only and do not modify the-License. You may add Your own attribution notices within Derivative Works that-You distribute, alongside or as an addendum to the NOTICE text from the Work,-provided that such additional attribution notices cannot be construed as-modifying the License.+ You may add Your own copyright statement to Your modifications and+ may provide additional or different license terms and conditions+ for use, reproduction, or distribution of Your modifications, or+ for any such Derivative Works as a whole, provided Your use,+ reproduction, and distribution of the Work otherwise complies with+ the conditions stated in this License. -You may add Your own copyright statement to Your modifications and may provide-additional or different license terms and conditions for use, reproduction, or-distribution of Your modifications, or for any such Derivative Works as a-whole, provided Your use, reproduction, and distribution of the Work otherwise-complies with the conditions stated in this License.+ 5. Submission of Contributions. Unless You explicitly state otherwise,+ any Contribution intentionally submitted for inclusion in the Work+ by You to the Licensor shall be under the terms and conditions of+ this License, without any additional terms or conditions.+ Notwithstanding the above, nothing herein shall supersede or modify+ the terms of any separate license agreement you may have executed+ with Licensor regarding such Contributions. -5. Submission of Contributions. Unless You explicitly state otherwise, any-Contribution intentionally submitted for inclusion in the Work by You to the-Licensor shall be under the terms and conditions of this License, without any-additional terms or conditions. Notwithstanding the above, nothing herein-shall supersede or modify the terms of any separate license agreement you may-have executed with Licensor regarding such Contributions.+ 6. Trademarks. This License does not grant permission to use the trade+ names, trademarks, service marks, or product names of the Licensor,+ except as required for reasonable and customary use in describing the+ origin of the Work and reproducing the content of the NOTICE file. -6. Trademarks. This License does not grant permission to use the trade names,-trademarks, service marks, or product names of the Licensor, except as-required for reasonable and customary use in describing the origin of the Work-and reproducing the content of the NOTICE file.+ 7. Disclaimer of Warranty. Unless required by applicable law or+ agreed to in writing, Licensor provides the Work (and each+ Contributor provides its Contributions) on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+ implied, including, without limitation, any warranties or conditions+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+ PARTICULAR PURPOSE. You are solely responsible for determining the+ appropriateness of using or redistributing the Work and assume any+ risks associated with Your exercise of permissions under this License. -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in-writing, Licensor provides the Work (and each Contributor provides its-Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY-KIND, either express or implied, including, without limitation, any warranties-or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A-PARTICULAR PURPOSE. You are solely responsible for determining the-appropriateness of using or redistributing the Work and assume any risks-associated with Your exercise of permissions under this License.+ 8. Limitation of Liability. In no event and under no legal theory,+ whether in tort (including negligence), contract, or otherwise,+ unless required by applicable law (such as deliberate and grossly+ negligent acts) or agreed to in writing, shall any Contributor be+ liable to You for damages, including any direct, indirect, special,+ incidental, or consequential damages of any character arising as a+ result of this License or out of the use or inability to use the+ Work (including but not limited to damages for loss of goodwill,+ work stoppage, computer failure or malfunction, or any and all+ other commercial damages or losses), even if such Contributor+ has been advised of the possibility of such damages. -8. Limitation of Liability. In no event and under no legal theory, whether in-tort (including negligence), contract, or otherwise, unless required by-applicable law (such as deliberate and grossly negligent acts) or agreed to in-writing, shall any Contributor be liable to You for damages, including any-direct, indirect, special, incidental, or consequential damages of any-character arising as a result of this License or out of the use or inability-to use the Work (including but not limited to damages for loss of goodwill,-work stoppage, computer failure or malfunction, or any and all other-commercial damages or losses), even if such Contributor has been advised of-the possibility of such damages.+ 9. Accepting Warranty or Additional Liability. While redistributing+ the Work or Derivative Works thereof, You may choose to offer,+ and charge a fee for, acceptance of support, warranty, indemnity,+ or other liability obligations and/or rights consistent with this+ License. However, in accepting such obligations, You may act only+ on Your own behalf and on Your sole responsibility, not on behalf+ of any other Contributor, and only if You agree to indemnify,+ defend, and hold each Contributor harmless for any liability+ incurred by, or claims asserted against, such Contributor by reason+ of your accepting any such warranty or additional liability. -9. Accepting Warranty or Additional Liability. While redistributing the Work-or Derivative Works thereof, You may choose to offer, and charge a fee for,-acceptance of support, warranty, indemnity, or other liability obligations-and/or rights consistent with this License. However, in accepting such-obligations, You may act only on Your own behalf and on Your sole-responsibility, not on behalf of any other Contributor, and only if You agree-to indemnify, defend, and hold each Contributor harmless for any liability-incurred by, or claims asserted against, such Contributor by reason of your-accepting any such warranty or additional liability.+ END OF TERMS AND CONDITIONS -END OF TERMS AND CONDITIONS+ APPENDIX: How to apply the Apache License to your work.++ To apply the Apache License to your work, attach the following+ boilerplate notice, with the fields enclosed by brackets "[]"+ replaced with your own identifying information. (Don't include+ the brackets!) The text should be enclosed in the appropriate+ comment syntax for the file format. We also recommend that a+ file or class name and description of purpose be included on the+ same "printed page" as the copyright notice for easier+ identification within third-party archives.++ Copyright [yyyy] [name of copyright owner]++ Licensed under the Apache License, Version 2.0 (the "License");+ you may not use this file except in compliance with the License.+ You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++ Unless required by applicable law or agreed to in writing, software+ distributed under the License is distributed on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ See the License for the specific language governing permissions and+ limitations under the License.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
cmd/HocusPocus.hs view
@@ -87,7 +87,9 @@ MagicWormhole.PlainText received <- atomically $ MagicWormhole.receiveMessage conn case Aeson.eitherDecode (toS received) of Left err -> panic $ "Could not decode message: " <> show err- Right (MagicWormhole.Message message) -> pure message)+ Right (MagicWormhole.Message message) -> pure message+ Right (MagicWormhole.File _ _) -> pure $ "File transfer is not supported"+ Right (MagicWormhole.Directory _ _ _ _ _) -> pure $ "Directory transfer is not supported") -- | Bounce a trivial message to and from a Rendezvous server. bounce :: MagicWormhole.WebSocketEndpoint -> MagicWormhole.AppID -> IO ()@@ -114,6 +116,8 @@ case Aeson.eitherDecode (toS received) of Left err -> panic $ "Could not decode message: " <> show err Right (MagicWormhole.Message message) -> pure message+ Right (MagicWormhole.File _ _) -> pure $ "File transfer is not supported"+ Right (MagicWormhole.Directory _ _ _ _ _) -> pure $ "Directory transfer is not supported" password = Spake2.makePassword "potato"
magic-wormhole.cabal view
@@ -1,32 +1,27 @@--- This file has been generated from package.yaml by hpack version 0.17.1.+-- This file has been generated from package.yaml by hpack version 0.28.2. -- -- see: https://github.com/sol/hpack+--+-- hash: 70e0d0470150c88f241234f7c12f2f2e92a2dcc939f84e6da5db4c8ba17a06a5 name: magic-wormhole-version: 0.1.0+version: 0.2.0 synopsis: Interact with Magic Wormhole-description: Client library for interacting with a Magic Wormhole server.- .- Magic Wormhole is a technology for getting things from one computer to another, safely.- It does this by using a server to locate peers, and then using SPAKE2 encryption to- negotiate a secure connection to a peer. It is especially useful for sending files- and short messages to other humans.+description: Magic Wormhole is a scheme to get things from one computer to another,+ safely. .- You can learn more about Magic Wormhole by exploring the documentation on- the [canonical, Python- implementation](https://github.com/warner/magic-wormhole).+ This is a library for client-side interactions with a Magic Wormhole server. category: Crypto-homepage: https://github.com/LeastAuthority/haskell-magic-wormhole#readme-bug-reports: https://github.com/LeastAuthority/haskell-magic-wormhole/issues-maintainer: Jonathan M. Lange <jml@mumak.net>+homepage: https://github.com/leastauthority/haskell-magic-wormhole#readme+bug-reports: https://github.com/leastauthority/haskell-magic-wormhole/issues+author: Jonathan M. Lange <jml@mumak.net>,+ Ramakrishnan Muthukrishnan <ram@leastauthority.com>,+ Jean-Paul Calderone <jean-paul@leastauthority.com>+maintainer: Least Authority TFA GmbH license: Apache license-file: LICENSE build-type: Simple cabal-version: >= 1.10--extra-source-files:- CHANGELOG.md- data-files: tests/python/derive_phase_key.py tests/python/nacl_exchange.py@@ -35,18 +30,16 @@ source-repository head type: git- location: https://github.com/LeastAuthority/haskell-magic-wormhole+ location: https://github.com/leastauthority/haskell-magic-wormhole library hs-source-dirs: src default-extensions: NoImplicitPrelude OverloadedStrings TypeApplications- ghc-options: -Wall+ ghc-options: -Wall -Werror=incomplete-patterns build-depends:- base >= 4.9 && < 5- , protolude >= 0.2- , spake2 >= 0.4.1- , aeson+ aeson+ , base ==4.9.* , bytestring , containers , cryptonite@@ -55,10 +48,12 @@ , network , network-uri , pqueue+ , protolude >=0.2 , saltine+ , spake2 >=0.4 , stm , unordered-containers- , websockets+ , websockets >=0.8.0.0 exposed-modules: MagicWormhole MagicWormhole.Internal.ClientProtocol@@ -70,21 +65,25 @@ MagicWormhole.Internal.Sequential MagicWormhole.Internal.Versions MagicWormhole.Internal.WebSockets+ other-modules:+ Paths_magic_wormhole default-language: Haskell2010 executable hocus-pocus main-is: HocusPocus.hs+ other-modules:+ Paths_magic_wormhole hs-source-dirs: cmd default-extensions: NoImplicitPrelude OverloadedStrings TypeApplications- ghc-options: -Wall+ ghc-options: -Wall -Werror=incomplete-patterns build-depends:- base >= 4.9 && < 5- , protolude >= 0.2- , spake2 >= 0.4.1- , aeson+ aeson+ , base ==4.9.* , magic-wormhole , optparse-applicative+ , protolude >=0.2+ , spake2 >=0.4 , text default-language: Haskell2010 @@ -94,28 +93,30 @@ hs-source-dirs: tests default-extensions: NoImplicitPrelude OverloadedStrings TypeApplications- ghc-options: -Wall+ ghc-options: -Wall -Werror=incomplete-patterns build-depends:- base >= 4.9 && < 5- , protolude >= 0.2- , spake2 >= 0.4.1- , aeson+ aeson+ , base ==4.9.* , bytestring , hedgehog , magic-wormhole , memory , process+ , protolude >=0.2 , saltine+ , spake2 >=0.3 , stm , tasty , tasty-hedgehog , tasty-hspec other-modules: ClientProtocol+ FileTransfer Generator Integration Messages Pake Sequential WebSockets+ Paths_magic_wormhole default-language: Haskell2010
src/MagicWormhole.hs view
@@ -59,6 +59,7 @@ , Peer.withEncryptedConnection , ClientProtocol.Connection , Peer.EncryptedConnection+ , Peer.deriveKey -- *** Errors , ClientProtocol.PeerError , Versions.VersionsError@@ -75,6 +76,7 @@ -- However, Magic Wormhole comes with at least one built-in "application": message and file transfer. -- This Haskell implementation only supports sending and receiving a simple message. , FileTransfer.Offer(..)+ , FileTransfer.DirectoryMode(..) ) where import qualified MagicWormhole.Internal.ClientProtocol as ClientProtocol
src/MagicWormhole/Internal/FileTransfer.hs view
@@ -8,6 +8,8 @@ -- you can send an 'Offer' to share a simple text message. module MagicWormhole.Internal.FileTransfer ( Offer(..)+ -- * for tests+ , DirectoryMode(..) ) where import Protolude@@ -19,20 +21,61 @@ , (.=) , object , withObject+ , Value( String ) )+import Data.Aeson.Types (typeMismatch)+import System.Posix.Types (FileOffset)+import Numeric.Natural (Natural) -- | An offer made by a sender as part of the Magic Wormhole file transfer protocol. -- -- Currently only supports sending simple text messages. A full version would -- also support sending files and directories.-newtype Offer+data Offer -- | A simple text message.- = Message Text deriving (Eq, Show)+ = Message Text+ -- | Offer a File with filename and size.+ | File FilePath FileOffset+ -- | Offer a Directory+ | Directory+ { directoryMode :: DirectoryMode+ -- ^ Mode. Currently always "zipfile/deflated".+ , dirName :: Text+ -- ^ Directory Name.+ , zipSize :: Natural+ -- ^ size of the transmitted compressed data in bytes+ , numBytes :: Natural+ -- ^ estimated total size of the uncompressed directory+ , numFiles :: Natural+ -- ^ number of files and directories being sent+ } deriving (Eq, Show) instance ToJSON Offer where toJSON (Message text) = object [ "offer" .= object [ "message" .= text ] ]+ toJSON (File name size) = object [ "offer" .= object [ "file" .= object [ "filename" .= name, "filesize" .= fromEnum size ] ] ]+ toJSON (Directory mode dirname zipsize numbytes numfiles) = object [ "offer" .= object [ "directory" .= object [ "mode" .= mode, "dirname" .= dirname, "zipsize" .= zipsize, "numbytes" .= numbytes, "numfiles" .= numfiles ] ] ] instance FromJSON Offer where parseJSON = withObject "Offer" $ \obj -> do offer <- obj .: "offer"- Message <$> offer .: "message"+ asum [ Message <$> offer .: "message"+ , File+ <$> ((offer .: "file") >>= (.: "filename"))+ <*> (toEnum <$> ((offer .: "file") >>= (.: "filesize")))+ , Directory+ <$> ((offer .: "directory") >>= (.: "mode"))+ <*> ((offer .: "directory") >>= (.: "dirname"))+ <*> (toEnum <$> ((offer .: "directory") >>= (.: "zipsize")))+ <*> (toEnum <$> ((offer .: "directory") >>= (.: "numbytes")))+ <*> (toEnum <$> ((offer .: "directory") >>= (.: "numfiles")))+ ]++data DirectoryMode = ZipFileDeflated+ deriving (Eq, Show)++instance FromJSON DirectoryMode where+ parseJSON (String s) | s == "zipfile/deflated" = return ZipFileDeflated+ parseJSON o = typeMismatch "failed to parse Directory Mode" o++instance ToJSON DirectoryMode where+ toJSON ZipFileDeflated = String "zipfile/deflated"
src/MagicWormhole/Internal/Peer.hs view
@@ -7,6 +7,7 @@ , withEncryptedConnection , sendMessage , receiveMessage+ , deriveKey ) where import Protolude hiding (phase)@@ -17,6 +18,7 @@ , newTVar , readTVar )+import qualified Crypto.Saltine.Core.SecretBox as SecretBox import qualified Crypto.Spake2 as Spake2 import qualified MagicWormhole.Internal.ClientProtocol as ClientProtocol@@ -64,7 +66,6 @@ conn <- establishEncryption peer password runEncryptedConnection conn (action conn) - -- | A Magic Wormhole peer-to-peer application session. -- -- Construct one of these using 'withEncryptedConnection'.@@ -146,3 +147,10 @@ -- Obtain an 'EncryptedConnection' with 'withEncryptedConnection'. receiveMessage :: EncryptedConnection -> STM ClientProtocol.PlainText receiveMessage conn = snd <$> Sequential.next (inbound conn)+++-- | Derive a new key for the given purpose+--+-- Construct a new key from the encrypted connection's session key for the given purpose+deriveKey :: EncryptedConnection -> ClientProtocol.Purpose -> SecretBox.Key+deriveKey conn = ClientProtocol.deriveKey (sharedKey conn)
+ tests/FileTransfer.hs view
@@ -0,0 +1,18 @@+-- | Tests for serializing and deserializing FileTransfer messages+module FileTransfer (tests) where++import Protolude++import Data.Aeson (encode, eitherDecode)+import Hedgehog (forAll, property, tripping)+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.Hedgehog (testProperty)++import qualified Generator++tests :: IO TestTree+tests = pure $ testGroup "FileTransfer"+ [ testProperty "offer messages roundtrip" $ property $ do+ x <- forAll Generator.offerMessages+ tripping x encode eitherDecode+ ]
tests/Generator.hs view
@@ -7,6 +7,7 @@ , appIDs , phases , sides+ , offerMessages ) where import Protolude@@ -29,6 +30,10 @@ , Mailbox(..) , Mood(..) )+import qualified MagicWormhole.Internal.FileTransfer as F+ ( Offer(..)+ , DirectoryMode(..)+ ) clientMessages :: MonadGen m => m ClientMessage clientMessages = Gen.choice@@ -97,3 +102,20 @@ welcomeMessages :: MonadGen m => m WelcomeMessage welcomeMessages = WelcomeMessage <$> Gen.maybe (Gen.text (Range.linear 0 1024) Gen.unicode) <*> Gen.maybe (Gen.text (Range.linear 0 1024) Gen.unicode)++directoryModes :: MonadGen m => m F.DirectoryMode+directoryModes = Gen.choice+ [ return F.ZipFileDeflated+ ]++offerMessages :: MonadGen m => m F.Offer+offerMessages = Gen.choice+ [ F.Message <$> (Gen.text (Range.linear 0 1024) Gen.unicode)+ , F.File <$> toS <$> (Gen.text (Range.linear 0 100) Gen.unicode) <*> (fromIntegral <$> (Gen.int (Range.linear 0 maxBound)))+ , F.Directory+ <$> directoryModes -- (toS <$> (Gen.text (Range.linear 0 100) Gen.unicode))+ <*> (toS <$> (Gen.text (Range.linear 0 100) Gen.unicode))+ <*> (fromIntegral <$> (Gen.int (Range.linear 0 maxBound)))+ <*> (fromIntegral <$> (Gen.int (Range.linear 0 maxBound)))+ <*> (fromIntegral <$> (Gen.int (Range.linear 0 maxBound)))+ ]
tests/Tasty.hs view
@@ -9,6 +9,7 @@ import qualified Messages import qualified Sequential import qualified WebSockets+import qualified FileTransfer main :: IO () main = sequence tests >>= defaultMain . testGroup "MagicWormhole"@@ -16,6 +17,7 @@ tests = [ ClientProtocol.tests , Messages.tests+ , FileTransfer.tests , Sequential.tests , WebSockets.tests -- Put these at the end because they are slowest.