filter out control characters in error messages
authorJoey Hess <joeyh@joeyh.name>
Mon, 10 Apr 2023 17:38:14 +0000 (13:38 -0400)
committerJoey Hess <joeyh@joeyh.name>
Mon, 10 Apr 2023 17:50:51 +0000 (13:50 -0400)
giveup changed to filter out control characters. (It is too low level to
make it use StringContainingQuotedPath.)

error still does not, but it should only be used for internal errors,
where the message is not attacker-controlled.

Changed a lot of existing error to giveup when it is not strictly an
internal error.

Of course, other exceptions can still be thrown, either by code in
git-annex, or a library, that include some attacker-controlled value.
This does not guard against those.

Sponsored-by: Noam Kremen on Patreon
69 files changed:
Annex/Branch.hs
Annex/GitOverlay.hs
Annex/Import.hs
Annex/Ssh.hs
Assistant/DeleteRemote.hs
Assistant/MakeRemote.hs
Assistant/MakeRepo.hs
Assistant/Pairing/MakeRemote.hs
Assistant/Ssh.hs
Assistant/Threads/Merger.hs
Assistant/Threads/TransferWatcher.hs
Assistant/Upgrade.hs
Assistant/WebApp/Configurators/Delete.hs
Assistant/WebApp/Configurators/Edit.hs
Assistant/WebApp/Configurators/Pairing.hs
Assistant/WebApp/Page.hs
Backend/Hash.hs
CmdLine/GitRemoteTorAnnex.hs
CmdLine/Seek.hs
Command/AddUrl.hs
Command/Fix.hs
Command/ImportFeed.hs
Command/Log.hs
Command/ReKey.hs
Command/Reinject.hs
Command/RemoteDaemon.hs
Command/ResolveMerge.hs
Command/SetKey.hs
Command/Smudge.hs
Command/TestRemote.hs
Command/TransferKeys.hs
Command/Undo.hs
Command/Unlock.hs
Command/Whereis.hs
Creds.hs
Crypto.hs
Database/Benchmark.hs
Database/Handle.hs
Git.hs
Git/CatFile.hs
Git/CheckAttr.hs
Git/Construct.hs
Git/DiffTree.hs
Git/PktLine.hs
Git/Sha.hs
Git/Tree.hs
Git/UnionMerge.hs
Limit.hs
Messages/Internal.hs
P2P/Annex.hs
Remote/BitTorrent.hs
Remote/Ddar.hs
Remote/GCrypt.hs
Remote/Helper/Encryptable.hs
Remote/Helper/Ssh.hs
Remote/HttpAlso.hs
Remote/P2P.hs
Remote/Rsync.hs
Remote/WebDAV.hs
RemoteDaemon/Core.hs
Test.hs
Utility/AuthToken.hs
Utility/Base64.hs
Utility/Exception.hs
Utility/Lsof.hs
Utility/SafeOutput.hs [new file with mode: 0644]
Utility/WebApp.hs
doc/todo/terminal_escapes_in_filenames.mdwn
git-annex.cabal

index 37bf6e3a6bce58e6e78e0370f2519d021575227f..d3caf08169661e8098ad5b5cfd929700658667b7 100644 (file)
@@ -130,7 +130,7 @@ getBranch = maybe (hasOrigin >>= go >>= use) return =<< branchsha
                        , Param $ fromRef name
                        , Param $ fromRef originname
                        ]
-               fromMaybe (error $ "failed to create " ++ fromRef name)
+               fromMaybe (giveup $ "failed to create " ++ fromRef name)
                        <$> branchsha
        go False = withIndex' True $ do
                -- Create the index file. This is not necessary,
index 568fd288140ef77e4063db0112e5a73c1862a1ef..5388c1bfc665f7e1bb9ff32899b2a323506d007c 100644 (file)
@@ -73,7 +73,7 @@ withWorkTree d a = withAltRepo
        (const a)
   where
        modlocation l@(Local {}) = l { worktree = Just (toRawFilePath d) }
-       modlocation _ = error "withWorkTree of non-local git repo"
+       modlocation _ = giveup "withWorkTree of non-local git repo"
 
 {- Runs an action with the git index file and HEAD, and a few other
  - files that are related to the work tree coming from an overlay
index 52c0aa1581e68a81cf3272255d5bf90e30fe5f78..68c8aa8281e9deaf4fc36e96d626e0f3af321a26 100644 (file)
@@ -458,10 +458,10 @@ importKeys remote importtreeconfig importcontent thirdpartypopulated importablec
        gochunked db c
                -- Downloading cannot be done when chunked, since only
                -- the first chunk is processed before returning.
-               | importcontent = error "importKeys does not support downloading chunked import"
+               | importcontent = giveup "importKeys does not support downloading chunked import"
                -- Chunked import is currently only used by thirdpartypopulated
                -- remotes.
-               | not thirdpartypopulated = error "importKeys does not support chunked import when not thirdpartypopulated"
+               | not thirdpartypopulated = giveup "importKeys does not support chunked import when not thirdpartypopulated"
                | otherwise = do
                        l <- forM (importableContentsSubTree c) $ \(loc, i) -> do
                                let loc' = importableContentsChunkFullLocation (importableContentsSubDir c) loc
index 2e45198fe576e1143daca7cd1751dda967662142..17124cdfb2339af601cab4c5bcb67510dfd58b9c 100644 (file)
@@ -432,7 +432,7 @@ sshOptionsTo remote gc localr
                        ( unchanged
                        , do
                                let port = Git.Url.port remote
-                               let sshhost = either error id (mkSshHost host)
+                               let sshhost = either giveup id (mkSshHost host)
                                (msockfile, cacheparams) <- sshCachingInfo (sshhost, port)
                                case msockfile of
                                        Nothing -> use []
index 07de5744af14852f181acb52cf1f5d16bef9212c..fa788f086f29baf10bf467a7c91be928943a50fa 100644 (file)
@@ -31,7 +31,7 @@ import qualified Data.Text as T
  - Remote data. -}
 disableRemote :: UUID -> Assistant Remote
 disableRemote uuid = do
-       remote <- fromMaybe (error "unknown remote")
+       remote <- fromMaybe (giveup "unknown remote")
                <$> liftAnnex (Remote.remoteFromUUID uuid)
        liftAnnex $ do
                inRepo $ Git.Remote.Remove.remove (Remote.name remote)
@@ -57,7 +57,7 @@ removableRemote urlrenderer uuid = getkeys >>= \case
        Just keys
                | null keys -> finishRemovingRemote urlrenderer uuid
                | otherwise -> do
-                       r <- fromMaybe (error "unknown remote")
+                       r <- fromMaybe (giveup "unknown remote")
                                <$> liftAnnex (Remote.remoteFromUUID uuid)
                        mapM_ (queueremaining r) keys
        Nothing -> noop
index 46daa33a04bf051d341cf947080e2f1a53b744d2..3d3c178f6536f5e759147656644b858abfb3e6b1 100644 (file)
@@ -47,7 +47,7 @@ addRemote :: Annex RemoteName -> Annex Remote
 addRemote a = do
        name <- a
        remotesChanged
-       maybe (error "failed to add remote") return
+       maybe (giveup "failed to add remote") return
                =<< Remote.byName (Just name)
 
 {- Inits a rsync special remote, and returns its name. -}
@@ -94,7 +94,7 @@ initSpecialRemote name remotetype mcreds config = go 0
 enableSpecialRemote :: SpecialRemoteMaker
 enableSpecialRemote name remotetype mcreds config =
        Annex.SpecialRemote.findExisting name >>= \case
-               [] -> error $ "Cannot find a special remote named " ++ name
+               [] -> giveup $ "Cannot find a special remote named " ++ name
                ((u, c, mcu):_) -> setupSpecialRemote' False name remotetype config mcreds (Just u, R.Enable c, c) mcu
 
 setupSpecialRemote :: RemoteName -> RemoteType -> R.RemoteConfig -> Maybe CredPair -> (Maybe UUID, R.SetupStage, R.RemoteConfig) -> Maybe (Annex.SpecialRemote.ConfigFrom UUID) -> Annex RemoteName
index e87701f32b9435704774a31fcb5f76f1cfc2a4d0..ca3be78a5f064f3338fdcdce63e6a8671fe7ab0a 100644 (file)
@@ -34,7 +34,7 @@ makeRepo path bare = ifM (probeRepoExists path)
                (transcript, ok) <-
                        processTranscript "git" (toCommand params) Nothing
                unless ok $
-                       error $ "git init failed!\nOutput:\n" ++ transcript
+                       giveup $ "git init failed!\nOutput:\n" ++ transcript
                return True
        )
   where
index cea2b635b7467b4479853a622032f6d0d205a381..69402e2e3de227d66944f18788814995c713e567 100644 (file)
@@ -24,11 +24,11 @@ import qualified Data.Text as T
  - side can immediately begin syncing. -}
 setupAuthorizedKeys :: PairMsg -> FilePath -> IO ()
 setupAuthorizedKeys msg repodir = case validateSshPubKey $ remoteSshPubKey $ pairMsgData msg of
-       Left err -> error err
+       Left err -> giveup err
        Right pubkey -> do
                absdir <- fromRawFilePath <$> absPath (toRawFilePath repodir)
                unlessM (liftIO $ addAuthorizedKeys True absdir pubkey) $
-                       error "failed setting up ssh authorized keys"
+                       giveup "failed setting up ssh authorized keys"
 
 {- When local pairing is complete, this is used to set up the remote for
  - the host we paired with. -}
index c392d54eb8eafe55522d38fc50d141f5ae040c6a..3f472a533255e92a0edbf559c60dd33e4237f812 100644 (file)
@@ -68,7 +68,7 @@ sshOpt k v = concat ["-o", k, "=", v]
 
 {- user@host or host -}
 genSshHost :: Text -> Maybe Text -> SshHost
-genSshHost host user = either error id $ mkSshHost $
+genSshHost host user = either giveup id $ mkSshHost $
        maybe "" (\v -> T.unpack v ++ "@") user ++ T.unpack host
 
 {- Generates a ssh or rsync url from a SshData. -}
@@ -218,7 +218,7 @@ genSshKeyPair = withTmpDir "git-annex-keygen" $ \dir -> do
                , Param "-f", File $ dir </> "key"
                ]
        unless ok $
-               error "ssh-keygen failed"
+               giveup "ssh-keygen failed"
        SshKeyPair
                <$> readFile (dir </> "key.pub")
                <*> readFile (dir </> "key")
index 01f7200801fd7ce1c450f9a7c93e55b359aa9fe1..ab4a9e47203e257b407c31f79d43ca617160ed35 100644 (file)
@@ -58,7 +58,7 @@ runHandler handler file _filestatus =
 
 {- Called when there's an error with inotify. -}
 onErr :: Handler
-onErr = error
+onErr = giveup
 
 {- Called when a new branch ref is written, or a branch ref is modified.
  -
index 4c80239d2b7c5d839f6ad21249ee75518e3fcbc3..d692a3ffd0cbfb882ebb190bfadebccf5a47a4a0 100644 (file)
@@ -53,7 +53,7 @@ runHandler handler file _filestatus =
 
 {- Called when there's an error with inotify. -}
 onErr :: Handler
-onErr = error
+onErr = giveup
 
 {- Called when a new transfer information file is written. -}
 onAdd :: Handler
index 5b8a49ebf615a91edb2d2519a336350d38b53ac2..419c133a62f2d6b2e3c043d24884a572e0f5d5f1 100644 (file)
@@ -205,7 +205,7 @@ upgradeToDistribution newdir cleanup distributionfile = do
                                , Param "--directory", File tmpdir
                                ]
                        unless tarok $
-                               error $ "failed to untar " ++ distributionfile
+                               giveup $ "failed to untar " ++ distributionfile
                        sanitycheck $ tmpdir </> installBase
                        installby R.rename newdir (tmpdir </> installBase)
                let deleteold = do
@@ -218,7 +218,7 @@ upgradeToDistribution newdir cleanup distributionfile = do
 #endif
        sanitycheck dir = 
                unlessM (doesDirectoryExist dir) $
-                       error $ "did not find " ++ dir ++ " in " ++ distributionfile
+                       giveup $ "did not find " ++ dir ++ " in " ++ distributionfile
        makeorigsymlink olddir = do
                let origdir = fromRawFilePath (parentDir (toRawFilePath olddir)) </> installBase
                removeWhenExistsWith R.removeLink (toRawFilePath origdir)
@@ -227,7 +227,7 @@ upgradeToDistribution newdir cleanup distributionfile = do
 {- Finds where the old version was installed. -}
 oldVersionLocation :: IO FilePath
 oldVersionLocation = readProgramFile >>= \case
-       Nothing -> error "Cannot find old distribution bundle; not upgrading."
+       Nothing -> giveup "Cannot find old distribution bundle; not upgrading."
        Just pf -> do
                let pdir = fromRawFilePath $ parentDir $ toRawFilePath pf
 #ifdef darwin_HOST_OS
@@ -240,7 +240,7 @@ oldVersionLocation = readProgramFile >>= \case
                let olddir = pdir
 #endif
                when (null olddir) $
-                       error $ "Cannot find old distribution bundle; not upgrading. (Looked in " ++ pdir ++ ")"
+                       giveup $ "Cannot find old distribution bundle; not upgrading. (Looked in " ++ pdir ++ ")"
                return olddir
 
 {- Finds a place to install the new version.
index 42d904f0225e7f09053069e7d6d4ff5cbae27e3d..333e13656a0ffe49540e6699b2bb2f24e14d36d3 100644 (file)
@@ -34,7 +34,7 @@ notCurrentRepo uuid a = do
                then redirect DeleteCurrentRepositoryR
                else go =<< liftAnnex (Remote.remoteFromUUID uuid)
   where
-       go Nothing = error "Unknown UUID"
+       go Nothing = giveup "Unknown UUID"
        go (Just _) = a
 
 getDeleteRepositoryR :: UUID -> Handler Html
@@ -45,7 +45,7 @@ getDeleteRepositoryR uuid = notCurrentRepo uuid $ do
 
 getStartDeleteRepositoryR :: UUID -> Handler Html
 getStartDeleteRepositoryR uuid = do
-       remote <- fromMaybe (error "unknown remote")
+       remote <- fromMaybe (giveup "unknown remote")
                <$> liftAnnex (Remote.remoteFromUUID uuid)
        liftAnnex $ do
                trustSet uuid UnTrusted
index 3e098189368b67b46037d905a585fae27f35552e..65da2d588e717d586642d0d24f816f93ec573590 100644 (file)
@@ -203,7 +203,7 @@ editForm new (RepoUUID uuid)
                mremote <- liftAnnex $ Remote.remoteFromUUID uuid
                when (mremote == Nothing) $
                        whenM ((/=) uuid <$> liftAnnex getUUID) $
-                               error "unknown remote"
+                               giveup "unknown remote"
                curr <- liftAnnex $ getRepoConfig uuid mremote
                liftAnnex $ checkAssociatedDirectory curr mremote
                mrepo <- liftAnnex $
index 1f01fa9be6af86704fa7d0d13c5da9e9e912061f..ceff21a3bf38e91cdd75bd6ab0ce3aea627bb4f0 100644 (file)
@@ -216,10 +216,10 @@ startLocalPairing stage oncancel alert muuid displaysecret secret = do
         - background. -}
        thread <- liftAssistant $ asIO $ do
                keypair <- liftIO $ genSshKeyPair
-               let pubkey = either error id $ validateSshPubKey $ sshPubKey keypair
+               let pubkey = either giveup id $ validateSshPubKey $ sshPubKey keypair
                pairdata <- liftIO $ PairData
                        <$> getHostname
-                       <*> (either error id <$> myUserName)
+                       <*> (either giveup id <$> myUserName)
                        <*> pure reldir
                        <*> pure pubkey
                        <*> (maybe genUUID return muuid)
index 07a33ea7fe3a85f22c1c05f06042092188935b0d..ee7491a688285819a324d2f6ce0cab170c1012a5 100644 (file)
@@ -67,7 +67,7 @@ customPage' with_longpolling navbaritem content = do
                                        addScript $ StaticR js_longpolling_js
                                $(widgetFile "page")
                        withUrlRenderer $(Hamlet.hamletFile $ hamletTemplate "bootstrap")
-               Just msg -> error msg
+               Just msg -> giveup msg
   where
        navdetails i = (navBarName i, navBarRoute i, Just i == navbaritem)
 
index 6166d04e07eab2ce2a84ec14a1bb811b44dd238e..78ece712926cefa1976ad7b7f2b73787005c2319 100644 (file)
@@ -229,7 +229,7 @@ sha2Hasher (HashSize hashsize)
        | hashsize == 224 = mkHasher sha2_224 sha2_224_context
        | hashsize == 384 = mkHasher sha2_384 sha2_384_context
        | hashsize == 512 = mkHasher sha2_512 sha2_512_context
-       | otherwise = error $ "unsupported SHA2 size " ++ show hashsize
+       | otherwise = giveup $ "unsupported SHA2 size " ++ show hashsize
 
 sha3Hasher :: HashSize -> Hasher
 sha3Hasher (HashSize hashsize)
@@ -237,13 +237,13 @@ sha3Hasher (HashSize hashsize)
        | hashsize == 224 = mkHasher sha3_224 sha3_224_context
        | hashsize == 384 = mkHasher sha3_384 sha3_384_context
        | hashsize == 512 = mkHasher sha3_512 sha3_512_context
-       | otherwise = error $ "unsupported SHA3 size " ++ show hashsize
+       | otherwise = giveup $ "unsupported SHA3 size " ++ show hashsize
 
 skeinHasher :: HashSize -> Hasher
 skeinHasher (HashSize hashsize)
        | hashsize == 256 = mkHasher skein256 skein256_context
        | hashsize == 512 = mkHasher skein512 skein512_context
-       | otherwise = error $ "unsupported SKEIN size " ++ show hashsize
+       | otherwise = giveup $ "unsupported SKEIN size " ++ show hashsize
 
 blake2bHasher :: HashSize -> Hasher
 blake2bHasher (HashSize hashsize)
@@ -252,25 +252,25 @@ blake2bHasher (HashSize hashsize)
        | hashsize == 160 = mkHasher blake2b_160 blake2b_160_context
        | hashsize == 224 = mkHasher blake2b_224 blake2b_224_context
        | hashsize == 384 = mkHasher blake2b_384 blake2b_384_context
-       | otherwise = error $ "unsupported BLAKE2B size " ++ show hashsize
+       | otherwise = giveup $ "unsupported BLAKE2B size " ++ show hashsize
 
 blake2bpHasher :: HashSize -> Hasher
 blake2bpHasher (HashSize hashsize)
        | hashsize == 512 = mkHasher blake2bp_512 blake2bp_512_context
-       | otherwise = error $ "unsupported BLAKE2BP size " ++ show hashsize
+       | otherwise = giveup $ "unsupported BLAKE2BP size " ++ show hashsize
 
 blake2sHasher :: HashSize -> Hasher
 blake2sHasher (HashSize hashsize)
        | hashsize == 256 = mkHasher blake2s_256 blake2s_256_context
        | hashsize == 160 = mkHasher blake2s_160 blake2s_160_context
        | hashsize == 224 = mkHasher blake2s_224 blake2s_224_context
-       | otherwise = error $ "unsupported BLAKE2S size " ++ show hashsize
+       | otherwise = giveup $ "unsupported BLAKE2S size " ++ show hashsize
 
 blake2spHasher :: HashSize -> Hasher
 blake2spHasher (HashSize hashsize)
        | hashsize == 256 = mkHasher blake2sp_256 blake2sp_256_context
        | hashsize == 224 = mkHasher blake2sp_224 blake2sp_224_context
-       | otherwise = error $ "unsupported BLAKE2SP size " ++ show hashsize
+       | otherwise = giveup $ "unsupported BLAKE2SP size " ++ show hashsize
 
 sha1Hasher :: Hasher
 sha1Hasher = mkHasher sha1 sha1_context
index d937b652c770fbf4c9f52a0689e634f6ff2dc388..3349304fb2ce9d85c9b6bb8c305e4d58d27583fe 100644 (file)
@@ -25,7 +25,7 @@ run (_remotename:address:[]) = forever $
                "capabilities" -> putStrLn "connect" >> ready
                "connect git-upload-pack" -> go UploadPack
                "connect git-receive-pack" -> go ReceivePack
-               l -> error $ "git-remote-helpers protocol error at " ++ show l
+               l -> giveup $ "git-remote-helpers protocol error at " ++ show l
   where
        (onionaddress, onionport)
                | '/' `elem` address = parseAddressPort $
index ab557d42abadfc50cde9732a26b064875108f134..b3bb8c3a86f1f0576fe473cd51be633d1e6ffe52 100644 (file)
@@ -313,7 +313,7 @@ withKeyOptions' ko auto mkkeyaction fallbackaction worktreeitems = do
                                        in keyaction lt (SeekInput [], k, bfp)
                                Nothing -> noop
                        unlessM (liftIO cleanup) $
-                               error ("git ls-tree " ++ Git.fromRef b ++ " failed")
+                               giveup ("git ls-tree " ++ Git.fromRef b ++ " failed")
        
        runfailedtransfers = do
                keyaction <- mkkeyaction
index 61e7c7de986c3b84e80c17a0ac41696770e5b8df..a76c54a2004a164fed8ee75db440ed96cbbedf99 100644 (file)
@@ -148,7 +148,7 @@ checkUrl addunlockedmatcher r o si u = do
        pathmax <- liftIO $ fileNameLengthLimit "."
        let deffile = fromMaybe (urlString2file u (pathdepthOption o) pathmax) (fileOption (downloadOptions o))
        go deffile =<< maybe
-               (error $ "unable to checkUrl of " ++ Remote.name r)
+               (giveup $ "unable to checkUrl of " ++ Remote.name r)
                (tryNonAsync . flip id u)
                (Remote.checkUrl r)
   where
index 83f0515f0153d66a0cea25451d19ad8f707ffa22..3cfa0d8f3901799f9605ed55c2140ad2040093b5 100644 (file)
@@ -76,7 +76,7 @@ breakHardLink file key obj = do
                let tmp' = toRawFilePath tmp
                mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file
                unlessM (checkedCopyFile key obj tmp' mode) $
-                       error "unable to break hard link"
+                       giveup "unable to break hard link"
                thawContent tmp'
                Database.Keys.storeInodeCaches key [tmp']
                modifyContentDir obj $ freezeContent obj
@@ -87,7 +87,7 @@ makeHardLink file key = do
        replaceWorkTreeFile (fromRawFilePath file) $ \tmp -> do
                mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file
                linkFromAnnex' key (toRawFilePath tmp) mode >>= \case
-                       LinkAnnexFailed -> error "unable to make hard link"
+                       LinkAnnexFailed -> giveup "unable to make hard link"
                        _ -> noop
        next $ return True
 
index 2146dadc5f10fcc5f1185f19c01cf3f7a4d4d7ba..fcddae4a4dbc32ca9ed08c38845cc57518c3f161 100644 (file)
@@ -232,7 +232,7 @@ performDownload' started addunlockedmatcher opts cache todownload = case locatio
                                                                return (Just [])
                                else do
                                        res <- tryNonAsync $ maybe
-                                               (error $ "unable to checkUrl of " ++ Remote.name r)
+                                               (giveup $ "unable to checkUrl of " ++ Remote.name r)
                                                (flip id url)
                                                (Remote.checkUrl r)
                                        case res of
index 2520311ea01b57b3584a591d4a5ce89a35530ad5..2dcac21cc995b18d18cf2f0bf37a10d12859b3f4 100644 (file)
@@ -281,7 +281,7 @@ parseRawChangeLine = go . words
        go _ = Nothing
 
 parseTimeStamp :: String -> POSIXTime
-parseTimeStamp = utcTimeToPOSIXSeconds . fromMaybe (error "bad timestamp") .
+parseTimeStamp = utcTimeToPOSIXSeconds . fromMaybe (giveup "bad timestamp") .
        parseTimeM True defaultTimeLocale "%s"
 
 showTimeStamp :: TimeZone -> POSIXTime -> String
index 76204609f53b50b15093f7080ae3c3ba5173607d..906d4b5dff67310da12cbd5f344a251664540bb8 100644 (file)
@@ -113,7 +113,7 @@ linkKey file oldkey newkey = ifM (isJust <$> isAnnexLink file)
                                replaceWorkTreeFile (fromRawFilePath file) $ \tmp -> do
                                        let tmp' = toRawFilePath tmp
                                        unlessM (checkedCopyFile oldkey oldobj tmp' Nothing) $
-                                               error "can't lock old key"
+                                               giveup "can't lock old key"
                                        thawContent tmp'
                ic <- withTSDelta (liftIO . genInodeCache file)
                case v of
index 2d3854242c9db87b88db98a585c28e756acf6ee5..363c44b20c7081f8787a7d83ec1861621259cd94 100644 (file)
@@ -103,7 +103,7 @@ notAnnexed src a =
 perform :: RawFilePath -> Key -> CommandPerform
 perform src key = ifM move
        ( next $ cleanup key
-       , error "failed"
+       , giveup "failed"
        )
   where
        move = checkDiskSpaceToGet key False $
index 728b16da6d938ce03732288da71a8ccc4fdacef0..114c0afcee2dcea1f8ac83d88191669a14494e88 100644 (file)
@@ -24,7 +24,7 @@ cmd = noCommit $
 
 run :: DaemonOptions -> CommandSeek
 run o
-       | stopDaemonOption o = error "--stop not implemented for remotedaemon"
+       | stopDaemonOption o = giveup "--stop not implemented for remotedaemon"
        | foregroundDaemonOption o = liftIO runInteractive
        | otherwise = do
 #ifndef mingw32_HOST_OS
index 4c0e8b61d51d0745f1ffd9d4e5e5b85899ec9c9b..aaa5c25ad2e6716e9ce802b8881dd98c85fe6d69 100644 (file)
@@ -28,7 +28,7 @@ start = starting "resolvemerge" (ActionItemOther Nothing) (SeekInput []) $ do
        us <- fromMaybe nobranch <$> inRepo Git.Branch.current
        d <- fromRawFilePath <$> fromRepo Git.localGitDir
        let merge_head = d </> "MERGE_HEAD"
-       them <- fromMaybe (error nomergehead) . extractSha
+       them <- fromMaybe (giveup nomergehead) . extractSha
                <$> liftIO (S.readFile merge_head)
        ifM (resolveMerge (Just us) them False)
                ( do
index 882bf3e0f32f79281c7d3c77f678444010efa451..263278189fd9e992cb3d859a93a4cbd834fac84e 100644 (file)
@@ -44,7 +44,7 @@ perform file key = do
                else return True
        if ok
                then next $ cleanup key
-               else error "mv failed!"
+               else giveup "move failed!"
 
 cleanup :: Key -> CommandCleanup
 cleanup key = do
index a5d8871998b2d5d88166f55148abe52483fb24ea..ae0b46a33a9983f29aa1ef42585132dd1d93e9cb 100644 (file)
@@ -191,7 +191,7 @@ clean' file mk passthrough discardreststdin emitpointer =
        postingest (Just k, _) = do
                logStatus k InfoPresent
                return k
-       postingest _ = error "could not add file to the annex"
+       postingest _ = giveup "could not add file to the annex"
 
        cfg = LockDownConfig
                { lockingFile = False
index d9f5931c2d99eceaae30efb8a3713508f40cc12d..32f48ab5be02e8e5317f3356870d72ef5f75afd7 100644 (file)
@@ -152,7 +152,7 @@ encryptionVariants cache dr = [noenc, sharedenc]
 
 -- Variant of a remote with exporttree disabled.
 disableExportTree :: RemoteVariantCache -> Remote -> Annex Remote
-disableExportTree cache r = maybe (error "failed disabling exportree") return 
+disableExportTree cache r = maybe (giveup "failed disabling exportree") return 
                =<< adjustRemoteConfig cache r (M.delete exportTreeField)
 
 -- Variant of a remote with exporttree enabled.
index 699febbfaaddd4bf0dcd4fe436b2c3cc96d7edcd..078f905eee4de383490295b1d8f61c0d2c00adde 100644 (file)
@@ -83,7 +83,7 @@ runRequests readh writeh a = do
                go rest
        go [] = noop
        go [""] = noop
-       go v = error $ "transferkeys protocol error: " ++ show v
+       go v = giveup $ "transferkeys protocol error: " ++ show v
 
        readrequests = liftIO $ split fieldSep <$> hGetContents readh
        sendresult b = liftIO $ do
index 4f6f42f525d27f4d78f125612c06e41475f26283..c56606c20dd1c65bb446ff051ae4029785b518fb 100644 (file)
@@ -5,6 +5,8 @@
  - Licensed under the GNU AGPL version 3 or higher.
  -}
 
+{-# LANGUAGE OverloadedStrings #-}
+
 module Command.Undo where
 
 import Command
index b165025b4360b66af86ab851324204384633cb91..d338c00dcd4df153563e3fa861419f56ead13a18 100644 (file)
@@ -58,7 +58,7 @@ perform dest key = do
                                case r of
                                        LinkAnnexOk -> return ()
                                        LinkAnnexNoop -> return ()
-                                       LinkAnnexFailed -> error "unlock failed"
+                                       LinkAnnexFailed -> giveup "unlock failed"
                        , liftIO $ writePointerFile (toRawFilePath tmp) key destmode
                        )
                withTSDelta (liftIO . genInodeCache (toRawFilePath tmp))
index 4fe9a0cf16784e88dabf83229ee347ec89f922c8..c6ddc88072945cbf59fe9c6d0ae9ec39c5be3212 100644 (file)
@@ -17,7 +17,6 @@ import Remote.Web (getWebUrls)
 import Annex.UUID
 import qualified Utility.Format
 import qualified Command.Find
-import Types.ActionItem
 
 import qualified Data.Map as M
 import qualified Data.Vector as V
index 78d38d664849dd112013e5dd78d1e7b51a98eaf9..95124f160d5919a4a332a7e5311f5f6c87386da9 100644 (file)
--- a/Creds.hs
+++ b/Creds.hs
@@ -150,7 +150,7 @@ getRemoteCredPair c gc storage = maybe fromcache (return . Just) =<< fromenv
                        writeCacheCredPair credpair storage
 
                        return $ Just credpair
-               _ -> error "bad creds"
+               _ -> giveup "bad creds"
 
 getRemoteCredPairFor :: String -> ParsedRemoteConfig -> RemoteGitConfig -> CredPairStorage -> Annex (Maybe CredPair)
 getRemoteCredPairFor this c gc storage = go =<< getRemoteCredPair c gc storage
index 41d4789d7fd31f63135d088b9639e2d743235a49..7f134a3cbcd927c1a29f4356e0e6e44332f10d29 100644 (file)
--- a/Crypto.hs
+++ b/Crypto.hs
@@ -73,7 +73,7 @@ cipherSize = 512
 
 cipherPassphrase :: Cipher -> String
 cipherPassphrase (Cipher c) = drop cipherBeginning c
-cipherPassphrase (MacOnlyCipher _) = error "MAC-only cipher"
+cipherPassphrase (MacOnlyCipher _) = giveup "MAC-only cipher"
 
 cipherMac :: Cipher -> String
 cipherMac (Cipher c) = take cipherBeginning c
index 613a30e5089348d575fb69d52a654086a29ad10a..81f353189144225cc03fdeeda2c8109d95e02269 100644 (file)
@@ -44,7 +44,7 @@ benchmarkDbs mode n = withTmpDirIn "." "benchmark" $ \tmpdir -> do
                        ]
                ]
 #else
-benchmarkDbs _ = error "not built with criterion, cannot benchmark"
+benchmarkDbs _ = giveup "not built with criterion, cannot benchmark"
 #endif
 
 #ifdef WITH_BENCHMARK
index da7a0e173a298a10ddde13532ff2dedbecc14155..5aea7a75b7752dc910430bb76866ddecf402f799 100644 (file)
@@ -84,7 +84,7 @@ queryDb (DbHandle _db _ jobs errvar) a = do
                Right r -> either throwIO return r
                Left BlockedIndefinitelyOnMVar -> do
                        err <- takeMVar errvar
-                       error $ "sqlite worker thread crashed: " ++ err
+                       giveup $ "sqlite worker thread crashed: " ++ err
 
 {- Writes a change to the database.
  -
diff --git a/Git.hs b/Git.hs
index 5e0b6980b27cb42ab8ff1d4f0bde91348f43480e..e567917ea1701f48ab5b839092402599bb65b0ed 100644 (file)
--- a/Git.hs
+++ b/Git.hs
@@ -68,7 +68,7 @@ repoLocation Repo { location = UnparseableUrl url } = url
 repoLocation Repo { location = Local { worktree = Just dir } } = fromRawFilePath dir
 repoLocation Repo { location = Local { gitdir = dir } } = fromRawFilePath dir
 repoLocation Repo { location = LocalUnknown dir } = fromRawFilePath dir
-repoLocation Repo { location = Unknown } = error "unknown repoLocation"
+repoLocation Repo { location = Unknown } = giveup "unknown repoLocation"
 
 {- Path to a repository. For non-bare, this is the worktree, for bare, 
  - it's the gitdir, and for URL repositories, is the path on the remote
@@ -78,8 +78,8 @@ repoPath Repo { location = Url u } = toRawFilePath $ unEscapeString $ uriPath u
 repoPath Repo { location = Local { worktree = Just d } } = d
 repoPath Repo { location = Local { gitdir = d } } = d
 repoPath Repo { location = LocalUnknown dir } = dir
-repoPath Repo { location = Unknown } = error "unknown repoPath"
-repoPath Repo { location = UnparseableUrl _u } = error "unknown repoPath"
+repoPath Repo { location = Unknown } = giveup "unknown repoPath"
+repoPath Repo { location = UnparseableUrl _u } = giveup "unknown repoPath"
 
 repoWorkTree :: Repo -> Maybe RawFilePath
 repoWorkTree Repo { location = Local { worktree = Just d } } = Just d
@@ -88,7 +88,7 @@ repoWorkTree _ = Nothing
 {- Path to a local repository's .git directory. -}
 localGitDir :: Repo -> RawFilePath
 localGitDir Repo { location = Local { gitdir = d } } = d
-localGitDir _ = error "unknown localGitDir"
+localGitDir _ = giveup "unknown localGitDir"
 
 {- Some code needs to vary between URL and normal repos,
  - or bare and non-bare, these functions help with that. -}
@@ -129,7 +129,7 @@ repoIsLocalUnknown _ = False
 
 assertLocal :: Repo -> a -> a
 assertLocal repo action
-       | repoIsUrl repo = error $ unwords
+       | repoIsUrl repo = giveup $ unwords
                [ "acting on non-local git repo"
                , repoDescribe repo
                , "not supported"
index f33ad493b79aecea5edde29fca4cb046cc1db6e2..daa41ad083efc4b3a2137db02170f99145b80760 100644 (file)
@@ -120,7 +120,7 @@ catObjectDetails h object = query (catFileProcess h) object newlinefallback $ \f
                        content <- readObjectContent from r
                        return $ Just (content, sha, objtype)
                Just DNE -> return Nothing
-               Nothing -> error $ "unknown response from git cat-file " ++ show (header, object)
+               Nothing -> giveup $ "unknown response from git cat-file " ++ show (header, object)
   where
        -- Slow fallback path for filenames containing newlines.
        newlinefallback = queryObjectType object (catFileGitRepo h) >>= \case
@@ -144,7 +144,7 @@ readObjectContent h (ParsedResp _ _ size) = do
        eatchar expected = do
                c <- hGetChar h
                when (c /= expected) $
-                       error $ "missing " ++ (show expected) ++ " from git cat-file"
+                       giveup $ "missing " ++ (show expected) ++ " from git cat-file"
 readObjectContent _ DNE = error "internal"
 
 {- Gets the size and type of an object, without reading its content. -}
index e4a7ea9d406e90d1a0e219b7ec84fb755098a827..f93c9075cfc85109ef378934f48ef390a46d5462 100644 (file)
@@ -54,7 +54,7 @@ checkAttrs (h, attrs, currdir) want file = do
        getvals l (x:xs) = case map snd $ filter (\(attr, _) -> attr == x) l of
                        ["unspecified"] -> "" : getvals l xs
                        [v] -> v : getvals l xs
-                       _ -> error $ "unable to determine " ++ x ++ " attribute of " ++ fromRawFilePath file
+                       _ -> giveup $ "unable to determine " ++ x ++ " attribute of " ++ fromRawFilePath file
 
        send to = B.hPutStr to $ file' `B.snoc` 0
        receive c from = do
index a64a9d5566891ef60684aad139ba7cfd35178436..82929d9076d787aa7ae16f608113cca37c9ed5d7 100644 (file)
@@ -86,7 +86,7 @@ fromAbsPath :: RawFilePath -> IO Repo
 fromAbsPath dir
        | absoluteGitPath dir = fromPath dir
        | otherwise =
-               error $ "internal error, " ++ show dir ++ " is not absolute"
+               giveup $ "internal error, " ++ show dir ++ " is not absolute"
 
 {- Construct a Repo for a remote's url.
  -
index d57ca385c0eb992b086f9d9bb504b229c04689b2..3be5cb980a31326e0cbe282571cae7a5b898bd2a 100644 (file)
@@ -113,8 +113,8 @@ parseDiffRaw l = go l
        go [] = []
        go (info:f:rest) = case A.parse (parserDiffRaw (L.toStrict f)) info of
                A.Done _ r -> r : go rest
-               A.Fail _ _ err -> error $ "diff-tree parse error: " ++ err
-       go (s:[]) = error $ "diff-tree parse error near \"" ++ decodeBL s ++ "\""
+               A.Fail _ _ err -> giveup $ "diff-tree parse error: " ++ err
+       go (s:[]) = giveup $ "diff-tree parse error near \"" ++ decodeBL s ++ "\""
 
 -- :<srcmode> SP <dstmode> SP <srcsha> SP <dstsha> SP <status>
 --
index a49cfc2b63e6735900a60984d38dcf2c658ad71d..95e8af26be81654ed51fbdc148327c40a2afc385 100644 (file)
@@ -31,6 +31,7 @@ import Text.Printf
 
 import Utility.PartialPrelude
 import Utility.FileSystemEncoding
+import Utility.Exception
 
 {- This is a variable length binary string, but its size is limited to
  - maxPktLineLength. Its serialization includes a 4 byte hexadecimal
@@ -96,7 +97,7 @@ encodePktLine b
 stringPktLine :: String -> PktLine
 stringPktLine s
        | length s > maxPktLineLength =
-               error "textPktLine called with too-long value"
+               giveup "textPktLine called with too-long value"
        | otherwise = PktLine (encodeBS s <> "\n")
 
 {- Sends a PktLine to a Handle, and flushes it so that it will be
index a66c34ee2c50592cf84cdfcb07f886633b1aa458..389bcc01a36994264c3e2a431fe4445e0765e109 100644 (file)
@@ -20,7 +20,7 @@ import Data.Char
 getSha :: String -> IO S.ByteString -> IO Sha
 getSha subcommand a = maybe bad return =<< extractSha <$> a
   where
-       bad = error $ "failed to read sha from git " ++ subcommand
+       bad = giveup $ "failed to read sha from git " ++ subcommand
 
 {- Extracts the Sha from a ByteString. 
  -
index 48ed126cfe9b2eeaa0617d579d7f083fb4509dcf..8c034be4cd8442c7b095e9658834095b8c983576 100644 (file)
@@ -62,7 +62,7 @@ data TreeContent
 getTree :: LsTree.LsTreeRecursive -> Ref -> Repo -> IO Tree
 getTree recursive r repo = do
        (l, cleanup) <- lsTreeWithObjects recursive r repo
-       let !t = either (\e -> error ("ls-tree parse error:" ++ e)) id
+       let !t = either (\e -> giveup ("ls-tree parse error:" ++ e)) id
                (extractTree l)
        void cleanup
        return t
@@ -254,7 +254,7 @@ adjustTree adjusttreeitem addtreeitems resolveaddconflict removefiles r repo =
                                        Just (TreeItem f m s) -> 
                                                let commit = TreeCommit f m s
                                                in go h wasmodified (commit:c) depth intree is
-                       _ -> error ("unexpected object type \"" ++ decodeBS (LsTree.typeobj i) ++ "\"")
+                       _ -> giveup ("unexpected object type \"" ++ decodeBS (LsTree.typeobj i) ++ "\"")
                | otherwise = return (c, wasmodified, i:is)
 
        adjustlist h depth ishere underhere l = do
index ffa57739754b07ad88e7e8b7f71709b8e2a6c30d..9f738da8448c0e51930b3413d0f399085a6d19d6 100644 (file)
@@ -78,7 +78,7 @@ doMerge hashhandle ch differ repo streamer = do
        go [] = noop
        go (info:file:rest) = mergeFile info file hashhandle ch >>=
                maybe (go rest) (\l -> streamer l >> go rest)
-       go (_:[]) = error $ "parse error " ++ show differ
+       go (_:[]) = giveup $ "parse error " ++ show differ
 
 {- Given an info line from a git raw diff, and the filename, generates
  - a line suitable for update-index that union merges the two sides of the
index 19a71185e3c09829d8f1cfb3d603a4d881415a14..f9e91b3aaa1d2e0fd41b75910cc99e78a08eb8f2 100644 (file)
--- a/Limit.hs
+++ b/Limit.hs
@@ -87,7 +87,7 @@ add l = Annex.changeState $ \s -> s { Annex.limit = prepend $ Annex.limit s }
 
 {- Adds a new syntax token. -}
 addSyntaxToken :: String -> Annex ()
-addSyntaxToken = either error add . Utility.Matcher.syntaxToken
+addSyntaxToken = either giveup add . Utility.Matcher.syntaxToken
 
 {- Adds a new limit. -}
 addLimit :: Either String (MatchFiles Annex) -> Annex ()
index 30cbafc1b0e656e47e9472fc3641488af2e03887..e88acf041c73e4e55674427b1324aca8cac82416 100644 (file)
@@ -105,4 +105,4 @@ outputSerialized = id
 waitOutputSerializedResponse :: (IO (Maybe SerializedOutputResponse)) -> SerializedOutputResponse -> IO ()
 waitOutputSerializedResponse getr r = tryIO getr >>= \case
        Right (Just r') | r' == r -> return ()
-       v -> error $ "serialized output protocol error; expected " ++ show r ++ " got " ++ show v
+       v -> giveup $ "serialized output protocol error; expected " ++ show r ++ " got " ++ show v
index 08177bec6e6b41370e320213f98be5c45e5b7d3a..a3e48085caccdd62225b7e4254b15e09648ff854 100644 (file)
@@ -225,7 +225,7 @@ runLocal runst runner a = case a of
                                                -- known. Force content
                                                -- verification.
                                                return (rightsize, MustVerify)
-                       Left e -> error $ describeProtoFailure e
+                       Left e -> giveup $ describeProtoFailure e
        
        sinkfile f (Offset o) checkchanged sender p ti = bracket setup cleanup go
          where
index 39c77867623b123e9c99b45b21c5edf75b4bc266..a237539904192e0f81043c6cbd19a89213ed5e09 100644 (file)
@@ -47,7 +47,7 @@ remote = RemoteType
        , enumerate = list
        , generate = gen
        , configParser = mkRemoteConfigParser []
-       , setup = error "not supported"
+       , setup = giveup "not supported"
        , exportSupported = exportUnsupported
        , importSupported = importUnsupported
        , thirdPartyPopulated = False
index 75d93e6a18102091526696e46807ade755976007..3fc3fdbafbff8777971442371e9877e4cdcc6714 100644 (file)
@@ -139,7 +139,7 @@ store ddarrepo = fileStorer $ \k src _p -> do
 
 {- Convert remote DdarRepo to host and path on remote end -}
 splitRemoteDdarRepo :: DdarRepo -> (SshHost, String)
-splitRemoteDdarRepo ddarrepo = (either error id $ mkSshHost host, ddarrepo')
+splitRemoteDdarRepo ddarrepo = (either giveup id $ mkSshHost host, ddarrepo')
   where
        (host, remainder) = span (/= ':') (ddarRepoLocation ddarrepo)
        ddarrepo' = drop 1 remainder
@@ -228,7 +228,7 @@ checkKey ddarrepo key = do
        directoryExists <- ddarDirectoryExists ddarrepo
        case directoryExists of
                Left e -> error e
-               Right True -> either error return
+               Right True -> either giveup return
                        =<< inDdarManifest ddarrepo key
                Right False -> return False
 
index 57e675e43fa4ec6db571cfd7970ff15f50866db3..1ab9461e6f0892c327fb1ddb73d4d09c1553615d 100644 (file)
@@ -197,7 +197,7 @@ rsyncTransport r gc
                let rsyncpath = if "/~/" `isPrefixOf` path
                        then drop 3 path
                        else path
-                   sshhost = either error id (mkSshHost host)
+                   sshhost = either giveup id (mkSshHost host)
                    mkopts = rsyncShell . (Param "ssh" :) 
                        <$> sshOptions ConsumeStdin (sshhost, Nothing) gc []
                in (mkopts, fromSshHost sshhost ++ ":" ++ rsyncpath, AccessGitAnnexShell)
@@ -239,7 +239,7 @@ gCryptSetup _ mu _ c gc = go $ fromProposedAccepted <$> M.lookup gitRepoField c
                                ]
                        (r:_)
                                | Git.repoLocation r == url -> noop
-                               | otherwise -> error "Another remote with the same name already exists."                
+                               | otherwise -> giveup "Another remote with the same name already exists."               
 
                pc <- either giveup return . parseRemoteConfig c'
                        =<< configParser remote c'
@@ -505,7 +505,7 @@ getGCryptId fast r gc
        | Git.repoIsLocal r || Git.repoIsLocalUnknown r = extract <$>
                liftIO (catchMaybeIO $ Git.Config.read r)
        | not fast = extract . liftM fst3 <$> getM (eitherToMaybe <$>)
-               [ Ssh.onRemote NoConsumeStdin r (\f p -> liftIO (Git.Config.fromPipe r f p Git.Config.ConfigList), return (Left $ error "configlist failed")) "configlist" [] []
+               [ Ssh.onRemote NoConsumeStdin r (\f p -> liftIO (Git.Config.fromPipe r f p Git.Config.ConfigList), return (Left $ giveup "configlist failed")) "configlist" [] []
                , getConfigViaRsync r gc
                ]
        | otherwise = return (Nothing, r)
index 29841b727f777b8f785e1b03f07208c2537c506a..f9625a56234c85219fa908fb71815889c7e74890 100644 (file)
@@ -331,4 +331,4 @@ toB64bs = w82s . B.unpack . B64.encode . B.pack . s2w8
 fromB64bs :: String -> String
 fromB64bs s = either (const bad) (w82s . B.unpack) (B64.decode $ B.pack $ s2w8 s)
   where
-       bad = error "bad base64 encoded data"
+       bad = giveup "bad base64 encoded data"
index c71a67ac6456efbfd8c870e8b9c46eda3b1b7ecf..9bd4990650fe025c63087a35a2628875be142c6b 100644 (file)
@@ -32,7 +32,7 @@ toRepo :: ConsumeStdin -> Git.Repo -> RemoteGitConfig -> SshCommand -> Annex (Fi
 toRepo cs r gc remotecmd = do
        let host = maybe
                (giveup "bad ssh url")
-               (either error id . mkSshHost)
+               (either giveup id . mkSshHost)
                (Git.Url.hostuser r)
        sshCommand cs (host, Git.Url.port r) gc remotecmd
 
index e77fb9a49885c7dc9d34e0220a5dee2de0df92fb..6402867d3271374b21dfab841e4c781d02d764d5 100644 (file)
@@ -103,7 +103,7 @@ cannotModify = giveup "httpalso special remote is read only"
 
 httpAlsoSetup :: SetupStage -> Maybe UUID -> Maybe CredPair -> RemoteConfig -> RemoteGitConfig -> Annex (RemoteConfig, UUID)
 httpAlsoSetup _ Nothing _ _ _ =
-       error "Must use --sameas when initializing a httpalso remote."
+       giveup "Must use --sameas when initializing a httpalso remote."
 httpAlsoSetup _ (Just u) _ c gc = do
        _url <- maybe (giveup "Specify url=")
                (return . fromProposedAccepted)
index 3ab66b56349e419d1dbab22d6a2eccb106b4da4e..959ecbbf58e4a99467acb38fa870b1e9fa17bdb0 100644 (file)
@@ -38,7 +38,7 @@ remote = RemoteType
        , enumerate = const (return [])
        , generate = \_ _ _ _ _ -> return Nothing
        , configParser = mkRemoteConfigParser []
-       , setup = error "P2P remotes are set up using git-annex p2p"
+       , setup = giveup "P2P remotes are set up using git-annex p2p"
        , exportSupported = exportUnsupported
        , importSupported = importUnsupported
        , thirdPartyPopulated = False
index 2fcb965a291d33c40016292348b18f73897ab92f..8b14c0b25c58e9e7f950cf3855033fb807ff536c 100644 (file)
@@ -179,7 +179,7 @@ rsyncTransport gc url
                case fromNull ["ssh"] (remoteAnnexRsyncTransport gc) of
                        "ssh":sshopts -> do
                                let (port, sshopts') = sshReadPort sshopts
-                                   userhost = either error id $ mkSshHost $ 
+                                   userhost = either giveup id $ mkSshHost $ 
                                        takeWhile (/= ':') url
                                return $ (Param "ssh":) <$> sshOptions ConsumeStdin
                                        (userhost, port) gc
index 518e14bfd12cd83b68015bca5031d5f2a60398da..e9e771d754547dc3f4177db736dc1d395aa0970f 100644 (file)
@@ -321,7 +321,7 @@ testDav url (Just (u, p)) = do
 
        user = toDavUser u
        pass = toDavPass p
-testDav _ Nothing = error "Need to configure webdav username and password."
+testDav _ Nothing = giveup "Need to configure webdav username and password."
 
 {- Tries to make all the parent directories in the WebDAV urls's path,
  - right down to the root.
@@ -407,7 +407,7 @@ choke :: IO (Either String a) -> IO a
 choke f = do
        x <- f
        case x of
-               Left e -> error e
+               Left e -> giveup e
                Right r -> return r
 
 data DavHandle = DavHandle DAVContext DavUser DavPass URLString
@@ -491,11 +491,11 @@ retrieveLegacyChunked d k p dav = liftIO $
                                inLocation l $
                                        snd <$> getContentM
   where
-       onerr = error "download failed"
+       onerr = giveup "download failed"
 
 checkKeyLegacyChunked :: DavHandle -> CheckPresent
 checkKeyLegacyChunked dav k = liftIO $
-       either error id <$> withStoredFilesLegacyChunked k dav onerr check
+       either giveup id <$> withStoredFilesLegacyChunked k dav onerr check
   where
        check [] = return $ Right True
        check (l:ls) = do
index ce29f7f7cc35091ec07f3eb27e5f5c8ef24fe46b..4ca248e315996e78127529cf501d077f93d26cdd 100644 (file)
@@ -40,7 +40,7 @@ runInteractive = do
        let reader = forever $ do
                l <- hGetLine readh
                case parseMessage l of
-                       Nothing -> error $ "protocol error: " ++ l
+                       Nothing -> giveup $ "protocol error: " ++ l
                        Just cmd -> atomically $ writeTChan ichan cmd
        let writer = forever $ do
                msg <- atomically $ readTChan ochan
diff --git a/Test.hs b/Test.hs
index b8f4adfc1e1583535ceb4413ff679477eeebd159..237eba82b9e407553178c0ea4fe2cce5bb762bdc 100644 (file)
--- a/Test.hs
+++ b/Test.hs
@@ -239,7 +239,7 @@ testRemote testvariants remotetype setupremote =
                innewrepo $ do
                        git_annex "init" [reponame, "--quiet"] "init"
                        setupremote remotename
-                       r <- annexeval $ either error return 
+                       r <- annexeval $ either giveup return 
                                =<< Remote.byName' remotename
                        cache <- Command.TestRemote.newRemoteVariantCache
                        unavailr <- annexeval $ Types.Remote.mkUnavailable r
index f5e2bfdcbc134e28af80cde85a1413543369cfbb..116e361bbe41307438170de77d134f8f7c8ac4bf 100644 (file)
@@ -20,6 +20,7 @@ module Utility.AuthToken (
 
 import qualified Utility.SimpleProtocol as Proto
 import Utility.Hash
+import Utility.Exception
 
 import Data.SecureMem
 import Data.Maybe
@@ -79,8 +80,8 @@ genAuthToken len = do
        g <- newGenIO :: IO SystemRandom
        return $
                case genBytes 512 g of
-                       Left e -> error $ "failed to generate auth token: " ++ show e
-                       Right (s, _) -> fromMaybe (error "auth token encoding failed") $
+                       Left e -> giveup $ "failed to generate auth token: " ++ show e
+                       Right (s, _) -> fromMaybe (giveup "auth token encoding failed") $
                                toAuthToken $ T.pack $ take len $
                                        show $ sha2_512 $ L.fromChunks [s]
 
index fec056e3bce21f8e26430123049fc59e01e5f314..32d90668232ef8ce8bbfd9e3c0f682e474844bd4 100644 (file)
@@ -11,6 +11,7 @@ module Utility.Base64 where
 
 import Utility.FileSystemEncoding
 import Utility.QuickCheck
+import Utility.Exception
 
 import qualified "sandi" Codec.Binary.Base64 as B64
 import Data.Maybe
@@ -36,12 +37,12 @@ fromB64Maybe' = either (const Nothing) Just . B64.decode
 fromB64 :: String -> String
 fromB64 = fromMaybe bad . fromB64Maybe
   where
-       bad = error "bad base64 encoded data"
+       bad = giveup "bad base64 encoded data"
 
 fromB64' :: B.ByteString -> B.ByteString
 fromB64' = fromMaybe bad . fromB64Maybe'
   where
-       bad = error "bad base64 encoded data"
+       bad = giveup "bad base64 encoded data"
 
 -- Only ascii strings are tested, because an arbitrary string may contain
 -- characters not encoded using the FileSystemEncoding, which would thus
index 4c60eac5977662e69bcb2232497a911b31dc158e..3d1a69912ad915e983fbdb21cd2e9183e16ceaa1 100644 (file)
@@ -36,13 +36,17 @@ import System.IO.Error (isDoesNotExistError, ioeGetErrorType)
 import GHC.IO.Exception (IOErrorType(..))
 
 import Utility.Data
+import Utility.SafeOutput
 
 {- Like error, this throws an exception. Unlike error, if this exception
  - is not caught, it won't generate a backtrace. So use this for situations
  - where there's a problem that the user is expected to see in some
- - circumstances. -}
+ - circumstances.
+ -
+ - Also, control characters are filtered out of the message.
+ -}
 giveup :: [Char] -> a
-giveup = errorWithoutStackTrace
+giveup = errorWithoutStackTrace . safeOutput
 
 {- Catches IO errors and returns a Bool -}
 catchBoolIO :: MonadCatch m => m Bool -> m Bool
index 5803dcd7f3bafe72ecea04b4b94e5f1f5e5ee66d..e8569ee0238d93fcd1da5323cf4df9de4bb0d809 100644 (file)
@@ -110,4 +110,4 @@ parse s = bundle $ go [] $ lines s
 
        splitnull = splitc '\0'
 
-       parsefail = error $ "failed to parse lsof output: " ++ show s
+       parsefail = giveup $ "failed to parse lsof output: " ++ show s
diff --git a/Utility/SafeOutput.hs b/Utility/SafeOutput.hs
new file mode 100644 (file)
index 0000000..0ca2d87
--- /dev/null
@@ -0,0 +1,24 @@
+{- Safe output to the terminal of possibly attacker-controlled strings,
+ - avoiding displaying control characters.
+ -
+ - Copyright 2023 Joey Hess <id@joeyh.name>
+ -
+ - License: BSD-2-clause
+ -}
+
+{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
+{-# OPTIONS_GHC -fno-warn-tabs #-}
+
+module Utility.SafeOutput (safeOutput) where
+
+import Data.Char
+import qualified Data.ByteString as S
+
+class SafeOutputtable t where
+       safeOutput :: t -> t
+
+instance SafeOutputtable String where
+       safeOutput = filter (not . isControl)
+
+instance SafeOutputtable S.ByteString where
+       safeOutput = S.filter (not . isControl . chr . fromIntegral)
index 81bd2d97be50ac686881de6c9aa6e6b8d50c27e0..497c2eb1bad79fa7a389f41ee28b4d45951083e2 100644 (file)
@@ -87,7 +87,7 @@ getSocket h = do
        -- getAddrInfo didn't used to work on windows; current status
        -- unknown.
        when (isJust h) $
-               error "getSocket with HostName not supported on this OS"
+               giveup "getSocket with HostName not supported on this OS"
        let addr = tupleToHostAddress (127,0,0,1)
        sock <- socket AF_INET Stream defaultProtocol
        preparesocket sock
@@ -99,7 +99,7 @@ getSocket h = do
        case (partition (\a -> addrFamily a == AF_INET) addrs) of
                (v4addr:_, _) -> go v4addr
                (_, v6addr:_) -> go v6addr
-               _ -> error "unable to bind to a local socket"
+               _ -> giveup "unable to bind to a local socket"
   where
        hostname = fromMaybe localhost h
        localhost = "localhost"
@@ -108,7 +108,7 @@ getSocket h = do
         - unknown reason on OSX. -} 
        go addr = go' 100 addr
        go' :: Int -> AddrInfo -> IO Socket
-       go' 0 _ = error "unable to bind to local socket"
+       go' 0 _ = giveup "unable to bind to local socket"
        go' n addr = do
                r <- tryIO $ bracketOnError (open addr) close (useaddr addr)
                either (const $ go' (pred n) addr) return r
@@ -129,9 +129,9 @@ webAppSessionBackend :: Yesod.Yesod y => y -> IO (Maybe Yesod.SessionBackend)
 webAppSessionBackend _ = do
        g <- newGenIO :: IO SystemRandom
        case genBytes 96 g of
-               Left e -> error $ "failed to generate random key: " ++ show e
+               Left e -> giveup $ "failed to generate random key: " ++ show e
                Right (s, _) -> case CS.initKey s of
-                       Left e -> error $ "failed to initialize key: " ++ show e
+                       Left e -> giveup $ "failed to initialize key: " ++ show e
                        Right key -> use key
   where
        timeout = 120 * 60 -- 120 minutes
index 9d1aa0278570f451aee66d81bc6e2608ea1fa812..575bcbfd788675ce9cf3f950570f8b5dd5f74cff 100644 (file)
@@ -36,7 +36,7 @@ behave more like git.
 > Update: Most git-annex commands now quote filenames, due to work on
 > ActionItem display. `git-annex find`, `git-annex info $file`,
 > and everywhere filenames get
-> embedded in error messages, warnings, info messages, still need to be done.
+> embedded in warnings, info messages, still need to be done.
 
 ----
 
@@ -59,3 +59,9 @@ out control characters. If such an url even can be parsed?
 
 Also: git-annex initremote with autoenable may be able to cause a remote
 with a malicious name to be set up?
+
+Also: Any place that an exception is thrown with an attacker-controlled value.
+`giveup` has been made to filter out control characters, but that leave
+other exceptions, including ones thrown by libraries. Catch all exceptions
+at top-level (of program and/or worker threads) and filter out control
+characters?
index 160a6c59e92b26ad41bd2801d0efd469978ea22f..f249e95af15b9af0f4b325e5760e4b3ba760c9ff 100644 (file)
@@ -1133,6 +1133,7 @@ Executable git-annex
     Utility.ResourcePool
     Utility.Rsync
     Utility.SafeCommand
+    Utility.SafeOutput
     Utility.Scheduled
     Utility.Scheduled.QuickCheck
     Utility.Shell