-------------------------------------------------------------------------------- -- This file is part of Hellnet -- -- Hellnet is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- Hellnet is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with Hellnet. If not, see . -------------------------------------------------------------------------------- import Control.Monad import qualified Data.ByteString.Lazy.UTF8 as BUL import qualified Data.ByteString.Lazy as BSL import qualified Data.Map as Map import Data.List import Data.Maybe import Hellnet import Hellnet.Meta as Meta import Hellnet.Network import Hellnet.Storage import Hellnet.Utils import System.Console.GetOpt import System.Environment import System.Exit import System.IO import System.Cmd import Text.HJson as JSON data Opts = Opts { encrypt :: Bool, encKey :: Maybe Key, updateMeta :: Bool } options :: [OptDescr (Opts -> Opts)] options = [ Option ['e'] ["encrypt"] (OptArg (\s o -> o {encrypt = True, encKey = maybe (Nothing) (Just . hexToHash) s}) "key") "Encrypt content (optionally with specified key)", Option ['u'] ["update-meta"] (NoArg (\o -> o {updateMeta = True})) "Automatically update meta before retrieval" ] defaultOptions = Opts { encrypt = False, encKey = Nothing, updateMeta = False } fetchMetaPrintResult :: KeyID -> String -> IO () fetchMetaPrintResult keyid mname = do result <- fetchMeta keyid mname let metaName = hashToHex (take 10 keyid) ++ ".../" ++ mname putStrLn $ case result of True -> "Meta "++ metaName ++" updated" False -> "Meta "++ metaName ++" unchanged" main = do argz <- getArgs keyAliases <- getKeyAliases let (optz, args, errs) = getOpt Permute options argz let opts = processOptions defaultOptions optz theKey <- if encrypt opts then (return . Just) =<< (maybe (genKey) (return) $ encKey opts) else return Nothing case args of ["update", keyidHex, mname] -> do keyid <- resolveKeyName keyidHex fetchMetaPrintResult keyid mname ["update", keyidHex] -> do keyid <- resolveKeyName keyidHex allmeta <- getMetaNames keyid mapM_ (fetchMetaPrintResult keyid) allmeta ["get", keyidHex, mname, mpath] -> do keyid <- resolveKeyName keyidHex when (updateMeta opts) (fetchMeta keyid mname >> return ()) vs <- findMetaValue keyid mname mpath case vs of Nothing -> error "Meta not found" Just a -> mapM_ (putStrLn . JSON.toString) $ a ["get", keyidHex, mname] -> do keyid <- resolveKeyName keyidHex when (updateMeta opts) (fetchMeta keyid mname >> return ()) metaM <- getMeta keyid mname case metaM of Nothing -> error "Meta not found" Just meta -> do contentM <- findMetaContent' meta case contentM of Nothing -> error "Meta content not found" Just content -> putStr content ["get", keyidHex] -> do keyid <- resolveKeyName keyidHex vs <- getMetaNames keyid mapM_ (putStrLn) vs ["edit", keyidHex, mname] -> do keyid <- resolveKeyName keyidHex when (updateMeta opts) (fetchMeta keyid mname >> return ()) v <- getMeta keyid mname case v of Nothing -> error "Meta not found" Just meta -> do cont <- findMetaContent' meta case cont of Nothing -> error "Meta content not found" Just cs -> do (fP, hdl) <- openTempFile "/tmp" "hellnetmeta" hPutStr hdl cs hClose hdl returnCode <- rawSystem "editor" [fP] case returnCode of ExitFailure i -> error $ "editor failed with code: " ++ show i ExitSuccess -> do modified <- readFile fP case JSON.fromString modified of Left errmsg -> error $ "JSON parsing error: " ++ errmsg Right _ -> do uri <- insertData theKey (BUL.fromString modified) newmetaM <- regenMeta $ meta {contentURI = uri} case newmetaM of Nothing -> error "Failed to re-sign meta" Just newmeta -> storeMeta newmeta ["replace", keyidHex, mname] -> do keyid <- resolveKeyName keyidHex when (updateMeta opts) (fetchMeta keyid mname >> return ()) contentV <- getContents case JSON.fromString contentV of Left errmsg -> error $ "JSON parsing error: " ++ errmsg Right _ -> do contentURIV <- insertData theKey (BUL.fromString contentV) newMetaM <- regenMeta Meta { contentURI = contentURIV, keyID = keyid, timestamp = 0, message = Nothing, signature = Nothing, metaName = mname } case newMetaM of Nothing -> error "Failed to sign meta" Just newMeta -> storeMeta newMeta ["genkey"] -> do putStrLn "Generating keys..." keyID <- generateKeyPair putStrLn $ "Your key ID is " ++ hashToHex keyID ["new", keyidHex, mname] -> do keyid <- resolveKeyName keyidHex emptyUri <- insertData theKey $ BUL.fromString "{}" newMetaM <- regenMeta Meta { contentURI = emptyUri, keyID = keyid, timestamp = 0, message = Nothing, signature = Nothing, metaName = mname } case newMetaM of Nothing -> error "Failed to sign meta" Just newMeta -> storeMeta newMeta ["alias", "add", name, keyidHex] -> do keyid <- resolveKeyName keyidHex storeKeyAliases $ Map.insert name keyid keyAliases ["alias", "rm", name] -> do storeKeyAliases $ Map.delete name keyAliases ["alias", "show", name] -> do putStrLn $ maybe (error "Alias not found") (hashToHex) $ Map.lookup name keyAliases ["alias", "list"] -> do mapM_ (\(k, v) -> putStrLn $ k ++ ": " ++ hashToHex v) $ Map.toList keyAliases otherwise -> let usageStrings = [ "", "update [] -- Update selected meta or all metas signed by key", "get -- output all meta names signed by key, one per line", "get -- display contents of meta", "get -- Display results of running jPath expression on meta content, one result per line", "edit -- launches `editor` to edit specified meta", "replace -- replaces meta contents with data from STDIN.", "genkey -- generates new key pair, displays key ID", "new -- creates new empty meta", "alias add -- adds new key alias", "alias rm -- removes key alias", "alias show -- resolves alias to key id", "alias list -- shows all the aliases with their names" ] in error $ usageInfo (intercalate "\n" $ map ("hell-meta "++) usageStrings) options ++ concat errs