diff options
author | joe <joe@jerkface.net> | 2014-04-21 20:07:23 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2014-04-21 20:07:23 -0400 |
commit | bb7640591e32e117c68b3ce54114bf562a67beaf (patch) | |
tree | 12a58921325b54abcd807484683db7214cde807a /kiki.hs | |
parent | 1a8986f93fbdf1b444bbe7ef6e45363cba5c78ba (diff) |
removed more unused bindings from kiki.hs
Diffstat (limited to 'kiki.hs')
-rw-r--r-- | kiki.hs | 348 |
1 files changed, 6 insertions, 342 deletions
@@ -38,9 +38,6 @@ import Control.Applicative | |||
38 | import System.Environment | 38 | import System.Environment |
39 | import System.Exit | 39 | import System.Exit |
40 | import System.IO (hPutStrLn,stderr) | 40 | import System.IO (hPutStrLn,stderr) |
41 | #if ! MIN_VERSION_base(4,6,0) | ||
42 | import ControlMaybe ( handleIO_ ) | ||
43 | #endif | ||
44 | import Data.Char | 41 | import Data.Char |
45 | import Control.Arrow (first,second) | 42 | import Control.Arrow (first,second) |
46 | -- import Data.Traversable hiding (mapM,forM,sequence) | 43 | -- import Data.Traversable hiding (mapM,forM,sequence) |
@@ -51,7 +48,7 @@ import Control.Arrow (first,second) | |||
51 | import qualified Data.Map as Map | 48 | import qualified Data.Map as Map |
52 | import DotLock | 49 | import DotLock |
53 | -- import Codec.Crypto.ECC.Base -- hecc package | 50 | -- import Codec.Crypto.ECC.Base -- hecc package |
54 | import Text.Printf | 51 | -- import Text.Printf |
55 | import qualified CryptoCoins as CryptoCoins | 52 | import qualified CryptoCoins as CryptoCoins |
56 | import LengthPrefixedBE | 53 | import LengthPrefixedBE |
57 | import Data.Binary.Put (putWord32be,runPut,putByteString) | 54 | import Data.Binary.Put (putWord32be,runPut,putByteString) |
@@ -62,10 +59,6 @@ import Base58 | |||
62 | 59 | ||
63 | -- instance Default S.ByteString where def = S.empty | 60 | -- instance Default S.ByteString where def = S.empty |
64 | 61 | ||
65 | -- DER-encoded elliptic curve ids | ||
66 | nistp256_id = 0x2a8648ce3d030107 | ||
67 | secp256k1_id = 0x2b8104000a | ||
68 | |||
69 | warn str = hPutStrLn stderr str | 62 | warn str = hPutStrLn stderr str |
70 | 63 | ||
71 | 64 | ||
@@ -113,20 +106,12 @@ getPackets = do | |||
113 | -} | 106 | -} |
114 | 107 | ||
115 | 108 | ||
116 | isEmbeddedSignature (EmbeddedSignaturePacket {}) = True | ||
117 | isEmbeddedSignature _ = False | ||
118 | |||
119 | isCertificationSig (CertificationSignature {}) = True | 109 | isCertificationSig (CertificationSignature {}) = True |
120 | isCertificationSig _ = True | 110 | isCertificationSig _ = True |
121 | 111 | ||
122 | issuer (IssuerPacket issuer) = Just issuer | ||
123 | issuer _ = Nothing | ||
124 | isSubkeySignature (SubkeySignature {}) = True | 112 | isSubkeySignature (SubkeySignature {}) = True |
125 | isSubkeySignature _ = False | 113 | isSubkeySignature _ = False |
126 | 114 | ||
127 | isPublicMaster k@(PublicKeyPacket {}) = not $ is_subkey k | ||
128 | isPublicMaster _ = False | ||
129 | |||
130 | verifyBindings keys nonkeys = (top ++ filter isSubkeySignature embedded,othersigs) | 115 | verifyBindings keys nonkeys = (top ++ filter isSubkeySignature embedded,othersigs) |
131 | where | 116 | where |
132 | verified = do | 117 | verified = do |
@@ -149,8 +134,6 @@ verifyBindings keys nonkeys = (top ++ filter isSubkeySignature embedded,othersig | |||
149 | guard (not . null $ signatures_over v) | 134 | guard (not . null $ signatures_over v) |
150 | return v | 135 | return v |
151 | 136 | ||
152 | grip k = drop 32 $ fingerprint k | ||
153 | |||
154 | smallpr k = drop 24 $ fingerprint k | 137 | smallpr k = drop 24 $ fingerprint k |
155 | 138 | ||
156 | 139 | ||
@@ -167,13 +150,6 @@ disjoint_fp ks = {- concatMap group2 $ -} transpose grouped | |||
167 | group2 [] = [] | 150 | group2 [] = [] |
168 | -} | 151 | -} |
169 | 152 | ||
170 | verifyBindingsEx :: [Packet] -> ([SignatureOver], [SignatureOver]) -- ^ (binding signatures, other signatures) | ||
171 | verifyBindingsEx pkts = bicat . unzip $ do | ||
172 | let (keys,_) = partition isKey pkts | ||
173 | keys <- disjoint_fp keys | ||
174 | return $ verifyBindings keys pkts | ||
175 | where | ||
176 | bicat (xs,ys) = (concat xs,concat ys) | ||
177 | 153 | ||
178 | getBindings :: | 154 | getBindings :: |
179 | [Packet] | 155 | [Packet] |
@@ -234,9 +210,11 @@ fpmatch grip key = | |||
234 | 210 | ||
235 | listKeys pkts = listKeysFiltered [] pkts | 211 | listKeys pkts = listKeysFiltered [] pkts |
236 | 212 | ||
213 | {- | ||
237 | ecc_curve k = printf "%x" num :: String | 214 | ecc_curve k = printf "%x" num :: String |
238 | where unmpi (MPI num) = num | 215 | where unmpi (MPI num) = num |
239 | num = maybe 0 unmpi $ lookup 'c' (key k) | 216 | num = maybe 0 unmpi $ lookup 'c' (key k) |
217 | -} | ||
240 | 218 | ||
241 | listKeysFiltered grips pkts = do | 219 | listKeysFiltered grips pkts = do |
242 | let (certs,bs) = getBindings pkts | 220 | let (certs,bs) = getBindings pkts |
@@ -326,213 +304,20 @@ listKeysFiltered grips pkts = do | |||
326 | 304 | ||
327 | 305 | ||
328 | 306 | ||
307 | {- | ||
329 | modifyUID (UserIDPacket str) = UserIDPacket str' | 308 | modifyUID (UserIDPacket str) = UserIDPacket str' |
330 | where | 309 | where |
331 | (fstname,rst) = break (==' ') str | 310 | (fstname,rst) = break (==' ') str |
332 | str' = mod fstname ++ rst | 311 | str' = mod fstname ++ rst |
333 | mod "Bob" = "Bob Fucking" | 312 | mod "Bob" = "Bob Slacking" |
334 | mod x = x | 313 | mod x = x |
335 | modifyUID other = other | 314 | modifyUID other = other |
315 | -} | ||
336 | 316 | ||
337 | todo = error "unimplemented" | ||
338 | |||
339 | #if ! MIN_VERSION_base(4,6,0) | ||
340 | lookupEnv var = | ||
341 | handleIO_ (return Nothing) $ fmap Just (getEnv var) | ||
342 | #endif | ||
343 | |||
344 | unmaybe def = fmap (maybe def id) | ||
345 | |||
346 | expandPath path (c:cs) | c/='/' = path ++ "/" ++ (c:cs) | ||
347 | | otherwise = c:cs | ||
348 | expandPath path [] = [] | ||
349 | 317 | ||
350 | 318 | ||
351 | -- type TimeStamp = Word32 | 319 | -- type TimeStamp = Word32 |
352 | 320 | ||
353 | -- | Attempts to lock each file in the list. | ||
354 | -- Returns a list of locks and a list of filenames | ||
355 | -- that could not be locked. | ||
356 | lockFiles :: [FilePath] -> IO ( [(DotLock,FilePath)], [FilePath] ) | ||
357 | lockFiles fs = do | ||
358 | ls <- forM fs $ \f -> do | ||
359 | lk <- dotlock_create f 0 | ||
360 | v <- flip (maybe $ return Nothing) lk $ \lk -> do | ||
361 | e <- dotlock_take lk (-1) | ||
362 | return $ if e==0 then Just lk | ||
363 | else Nothing | ||
364 | return (v,f) | ||
365 | let (lks, fails) = partition (isJust . fst) ls | ||
366 | return (map (\(lk,f)->(fromJust lk,f)) lks, map snd fails) | ||
367 | |||
368 | unlockFiles lks = forM_ lks $ \(lk,f) -> do | ||
369 | -- warn $ "unlocking "++show f | ||
370 | dotlock_release lk | ||
371 | |||
372 | {- | ||
373 | options_from_file :: | ||
374 | (forall a. [String] -> Term a -> IO (Either EvalExit a)) | ||
375 | -> Term b | ||
376 | -> (String,String,Term (Maybe String)) | ||
377 | -> ([String],Term (Maybe String)) | ||
378 | -> IO [String] | ||
379 | options_from_file unwrapCmd term (homevar,appdir,home) (optfile_alts,options_file) = doit | ||
380 | where | ||
381 | homedir = envhomedir <$> home | ||
382 | envhomedir opt = do | ||
383 | gnupghome <- lookupEnv homevar >>= | ||
384 | \d -> return $ d >>= guard . (/="") >> d | ||
385 | home <- flip fmap getHomeDirectory $ | ||
386 | \d -> fmap (const d) $ guard (d/="") | ||
387 | let homegnupg = (++('/':appdir)) <$> home | ||
388 | let val = (opt `mplus` gnupghome `mplus` homegnupg) | ||
389 | return $ val | ||
390 | |||
391 | doit = do | ||
392 | args <- getArgs | ||
393 | {- | ||
394 | let wants_help = | ||
395 | not . null $ filter cryForHelp args | ||
396 | where cryForHelp "--help" = True | ||
397 | cryForHelp "--version" = True | ||
398 | cryForHelp x = | ||
399 | and (zipWith (==) x "--help=") | ||
400 | -} | ||
401 | (o,h) <- do | ||
402 | val <- unwrapCmd args (liftA2 (,) options_file homedir) | ||
403 | case val of | ||
404 | Left e -> return (Nothing,Nothing) | ||
405 | Right (o,h) -> (o,) <$> h | ||
406 | ofile <- fmap listToMaybe . flip (maybe (return [])) h $ \h -> | ||
407 | let optfiles = map (second ((h++"/")++)) | ||
408 | (maybe optfile_alts' (:[]) o') | ||
409 | optfile_alts' = zip (False:repeat True) optfile_alts | ||
410 | o' = fmap (False,) o | ||
411 | in filterM (doesFileExist . snd) optfiles | ||
412 | args <- flip (maybe $ return args) ofile $ \(forgive,fname) -> do | ||
413 | let h' = fromJust h | ||
414 | newargs <- (:) <$> pure ("homedir "++h') <*> parseOptionFile fname | ||
415 | let toArgs = toHead ("--"++) . words | ||
416 | toHead f (x:xs) = f x : xs | ||
417 | toHead f [] = [] | ||
418 | voidTerm = fmap (const ()) | ||
419 | appendArgs as [] = return as | ||
420 | appendArgs as (configline:cs) = do | ||
421 | let xs = toArgs configline | ||
422 | w <-unwrap (xs++as) (voidTerm term,defTI) | ||
423 | case w of | ||
424 | Left _ -> appendArgs as cs | ||
425 | Right _ -> appendArgs (xs++as) cs | ||
426 | -- TODO: check errors if forgive = False | ||
427 | appendArgs args newargs | ||
428 | return args | ||
429 | |||
430 | runWithOptionsFile :: (Term (IO b), TermInfo) -> IO b | ||
431 | runWithOptionsFile (term,ti) = do | ||
432 | as <- options_from_file unwrapCmd | ||
433 | term | ||
434 | ("GNUPGHOME",".gnupg",opt_homedir) | ||
435 | (["keys.conf","gpg.conf-2","gpg.conf"] | ||
436 | ,opt_options) | ||
437 | q <- eval as (term , ti) | ||
438 | q | ||
439 | where | ||
440 | unwrapCmd args term = unwrap args (term,defTI) | ||
441 | |||
442 | runChoiceWithOptionsFile :: | ||
443 | (Term (IO b), TermInfo) -> [(Term (IO b), TermInfo)] -> IO b | ||
444 | runChoiceWithOptionsFile (realterm,ti) choices = do | ||
445 | as <- options_from_file unwrapCmd | ||
446 | realterm | ||
447 | ("GNUPGHOME",".gnupg",opt_homedir) | ||
448 | (["keys.conf","gpg.conf-2","gpg.conf"] | ||
449 | ,opt_options) | ||
450 | -- putStrLn $ "as = " ++ show as | ||
451 | q <- evalChoice as (realterm , ti) choices | ||
452 | q | ||
453 | where | ||
454 | unwrapCmd args t = | ||
455 | unwrapChoice args (realterm <:> t,ti) (map (neuter t) choices) | ||
456 | neuter term (t,ti) = (t <:> term, ti) | ||
457 | |||
458 | data Command = | ||
459 | List | ||
460 | | Autosign | ||
461 | deriving (Eq,Show,Read,Enum) | ||
462 | |||
463 | capitolizeFirstLetter (x:xs) = toUpper x : xs | ||
464 | capitolizeFirstLetter xs = xs | ||
465 | |||
466 | instance ArgVal Command where | ||
467 | converter = | ||
468 | ( maybe (Left $ text "unknown command") Right | ||
469 | . fmap fst . listToMaybe . reads | ||
470 | . capitolizeFirstLetter . map toLower | ||
471 | , text . map toLower . show | ||
472 | ) | ||
473 | class AutoMaybe a | ||
474 | instance AutoMaybe Command | ||
475 | instance (ArgVal a, AutoMaybe a) => ArgVal (Maybe a) where | ||
476 | converter = | ||
477 | ( toRight Just . fst converter | ||
478 | , maybe (text "(unspecified)") id . fmap (snd converter) | ||
479 | ) | ||
480 | |||
481 | toRight f (Right x) = Right (f x) | ||
482 | toRight f (Left y) = Left y | ||
483 | |||
484 | cmd :: Term Command | ||
485 | cmd = required . pos 0 Nothing $ posInfo | ||
486 | { posName = "command" | ||
487 | , posDoc = "What action to perform." | ||
488 | } | ||
489 | |||
490 | a <:> b = flip const <$> a <*> b | ||
491 | infixr 2 <:> | ||
492 | |||
493 | selectAction cmd actions = actions !! fromEnum cmd | ||
494 | |||
495 | cmdInfo :: ArgVal cmd => | ||
496 | cmd -> String -> Term a -> (cmd, (Term a, TermInfo)) | ||
497 | cmdInfo cmd doc action = | ||
498 | ( cmd | ||
499 | , ( action | ||
500 | , defTI { termName = print cmd | ||
501 | , termDoc = doc } ) ) | ||
502 | where | ||
503 | print = show . snd converter | ||
504 | |||
505 | cmdlist :: (Command, (Term (IO ()), TermInfo)) | ||
506 | cmdlist = cmdInfo List "list key pairs for which secrets are known" $ | ||
507 | (>>= putStrLn . listKeys . unMessage) <$> secret_packets | ||
508 | where unMessage (Message pkts) = pkts | ||
509 | |||
510 | cmdautosign = cmdInfo Autosign "auto-sign tor-style uids" $ | ||
511 | pure (putStrLn "autosign") | ||
512 | |||
513 | |||
514 | multiCommand :: | ||
515 | TermInfo | ||
516 | -> [(Command, (Term a, TermInfo))] | ||
517 | -> ( (Term a, TermInfo) | ||
518 | , [(Term a, TermInfo)] ) | ||
519 | multiCommand ti choices = | ||
520 | ( ( selectAction <$> cmd <*> sequenceA (map strip choices) | ||
521 | , ti ) | ||
522 | , map snd choices ) | ||
523 | where | ||
524 | selectAction cmd choices = | ||
525 | fromJust $ lookup (cmd::Command) choices | ||
526 | strip (cmd,(action,_)) = fmap (cmd,) action | ||
527 | -} | ||
528 | |||
529 | |||
530 | trimCR bs = fst $ S.spanEnd (\x -> x==10 || x==13) bs | ||
531 | |||
532 | guessKeyFormat 'P' "ssh-client" = "SSH" | ||
533 | guessKeyFormat 'S' "ssh-client" = "PEM" | ||
534 | guessKeyFormat 'S' "ssh-host" = "PEM" | ||
535 | guessKeyFormat _ _ = "PEM" -- "PGP" | ||
536 | 321 | ||
537 | readPublicKey :: Char8.ByteString -> RSAPublicKey | 322 | readPublicKey :: Char8.ByteString -> RSAPublicKey |
538 | readPublicKey bs = maybe er id $ do | 323 | readPublicKey bs = maybe er id $ do |
@@ -557,44 +342,6 @@ getPassphrase cmd = | |||
557 | 342 | ||
558 | #define HOMEOPTION (def &= explicit &= name "homedir" &= typDir ) | 343 | #define HOMEOPTION (def &= explicit &= name "homedir" &= typDir ) |
559 | 344 | ||
560 | writeOutKeyrings :: Map.Map FilePath t -> KeyDB -> IO () | ||
561 | writeOutKeyrings lkmap db = do | ||
562 | let ks = Map.elems db | ||
563 | fs = Map.keys (foldr unionfiles Map.empty ks) | ||
564 | where unionfiles (KeyData p _ _ _) m = | ||
565 | Map.union m (locations p) | ||
566 | fromfile f (KeyData p _ _ _) = Map.member f $ locations p | ||
567 | let s = do | ||
568 | f <- fs | ||
569 | let x = do | ||
570 | d@(KeyData p _ _ _) <- filter (fromfile f) (sortByHint f keyMappedPacket ks) | ||
571 | n <- maybeToList $ Map.lookup f (locations p) | ||
572 | flattenTop f (originallyPublic n) d | ||
573 | changes = filter isnew x | ||
574 | where isnew p = isNothing (Map.lookup f $ locations p) | ||
575 | {- | ||
576 | trace (unlines $ ( (f ++ ":") : map (showPacket . packet) x) ++ | ||
577 | ( "CHANGES: " : map ((" "++) . showPacket . packet) changes)) $ do | ||
578 | -} | ||
579 | return (f,(changes,x)) | ||
580 | towrites <- fmap catMaybes $ Control.Monad.forM s $ \(f,(changes,x)) -> do | ||
581 | let noop = return Nothing | ||
582 | write f = return (Just f) | ||
583 | case changes of | ||
584 | [] -> noop -- warn (f ++": nothing to do.") >> noop | ||
585 | cs -> case Map.lookup f lkmap of | ||
586 | Just lk -> do | ||
587 | forM_ cs $ \c -> warn $ f++": new "++showPacket (packet c) | ||
588 | write (f,lk,x) | ||
589 | Nothing -> do | ||
590 | forM_ cs $ \c -> warn $ f++": missing "++showPacket (packet c) | ||
591 | noop | ||
592 | forM_ towrites $ \(f,lk,x) -> do | ||
593 | let m = Message $ map packet x | ||
594 | -- warn $ "writing "++f | ||
595 | L.writeFile f (encode m) | ||
596 | |||
597 | |||
598 | 345 | ||
599 | toLast f [] = [] | 346 | toLast f [] = [] |
600 | toLast f [x] = [f x] | 347 | toLast f [x] = [f x] |
@@ -715,39 +462,6 @@ cannonical_eckey x y = 0x4:pad32(numToBytes x) ++ pad32(numToBytes y) :: [Word8] | |||
715 | where | 462 | where |
716 | zlen = 32 - length xs | 463 | zlen = 32 - length xs |
717 | 464 | ||
718 | oidToDER ns = S.pack $ b1 : concatMap encode ys | ||
719 | where | ||
720 | (xs,ys) = splitAt 2 ns | ||
721 | b1 = fromIntegral $ foldl' (\a b->a*40+b) 0 xs | ||
722 | encode x | x <= 127 = [fromIntegral x] | ||
723 | | otherwise = (\(x:xs)-> reverse (x:map (0x80 .|.) xs)) | ||
724 | (base128r x) | ||
725 | base128r n = unfoldr getbyte n | ||
726 | where | ||
727 | getbyte d = do | ||
728 | guard (d/=0) | ||
729 | let (q,b) = d `divMod` 128 | ||
730 | return (fromIntegral b,q) | ||
731 | |||
732 | nistp256=[1,2,840,10045,3,1,7] | ||
733 | nistp256_der=[0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07] | ||
734 | -- "\x2a\x86\x48\xce\x3d\x03\x01\x07" | ||
735 | {- OID Curve description Curve name | ||
736 | ---------------------------------------------------------------- | ||
737 | 1.2.840.10045.3.1.7 NIST Curve P-256 [FIPS 186-2] "NIST P-256" | ||
738 | 1.3.132.0.34 NIST Curve P-384 [FIPS 186-2] "NIST P-384" | ||
739 | 1.3.132.0.35 NIST Curve P-521 [FIPS 186-2] "NIST P-521" | ||
740 | |||
741 | Implementations MUST implement "NIST P-256", "NIST P-384" and "NIST | ||
742 | P-521". The hexadecimal representation used in the public and | ||
743 | private key encodings are: | ||
744 | |||
745 | Curve Name Len Hexadecimal representation of the OID | ||
746 | ---------------------------------------------------------------- | ||
747 | "NIST P-256" 8 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 | ||
748 | "NIST P-384" 6 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22 | ||
749 | "NIST P-521" 6 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23 | ||
750 | -} | ||
751 | 465 | ||
752 | bitcoinAddress network_id k = address | 466 | bitcoinAddress network_id k = address |
753 | where | 467 | where |
@@ -815,51 +529,6 @@ whoseKey rsakey db = filter matchkey (Map.elems db) | |||
815 | s2 <- signatures . Message $ [k,sub,subsig] | 529 | s2 <- signatures . Message $ [k,sub,subsig] |
816 | signatures_over $ verify (Message [sub]) s2 | 530 | signatures_over $ verify (Message [sub]) s2 |
817 | 531 | ||
818 | workingKey grip use_db = listToMaybe $ do | ||
819 | fp <- maybeToList grip | ||
820 | elm <- Map.toList use_db | ||
821 | guard $ matchSpec (KeyGrip fp) elm | ||
822 | return $ keyPacket (snd elm) | ||
823 | |||
824 | has_good_sig wk (KeyData k sigs uids subs) = any goodsig $ Map.toList uids | ||
825 | where | ||
826 | goodsig (uidstr,(sigs,_)) = not . null $ do | ||
827 | sig0 <- fmap (packet . fst) sigs | ||
828 | pre_ov <- signatures (Message [packet k, UserIDPacket uidstr, sig0]) | ||
829 | signatures_over $ verify (Message [wk]) pre_ov | ||
830 | |||
831 | markForImport | ||
832 | :: Ord d => | ||
833 | Map.Map String a | ||
834 | -> Maybe String | ||
835 | -> FilePath | ||
836 | -> Map.Map d KeyData | ||
837 | -> IO (Map.Map d KeyData) | ||
838 | markForImport margs grip pubring db = maybe (return db) import_db $ wantToImport | ||
839 | where wantToImport = mplus import_f importifauth_f | ||
840 | where | ||
841 | import_f = do Map.lookup "--import" margs | ||
842 | return dont_have | ||
843 | importifauth_f = do Map.lookup "--import-if-authentic" margs | ||
844 | return isauth | ||
845 | dont_have (KeyData p _ _ _) = not . Map.member pubring | ||
846 | $ locations p | ||
847 | isauth keydata = dont_have keydata && maybe False (`has_good_sig` keydata) wk | ||
848 | where wk = workingKey grip db | ||
849 | import_db dont_have = do | ||
850 | forM_ to_alters $ \(_,KeyData c _ _ _) -> | ||
851 | warn $ pubring ++ ": new "++showPacket (packet c) | ||
852 | let db' = Map.union (Map.fromList altered) | ||
853 | db | ||
854 | return db' | ||
855 | where | ||
856 | to_alters = filter (dont_have . snd) $ Map.toList db | ||
857 | altered = map (second append_loc) to_alters | ||
858 | append_loc (KeyData p a b c) = KeyData p' a b c | ||
859 | where p' = p { locations = Map.insert pubring | ||
860 | (origin (secretToPublic (packet p)) (-1)) | ||
861 | (locations p) | ||
862 | } | ||
863 | 532 | ||
864 | kiki_usage = do | 533 | kiki_usage = do |
865 | putStr . unlines $ | 534 | putStr . unlines $ |
@@ -1149,11 +818,6 @@ groupBindings pub = | |||
1149 | gs = {- filter matchgrip $ -} groupBy sameMaster (sortBy (comparing code) bindings') | 818 | gs = {- filter matchgrip $ -} groupBy sameMaster (sortBy (comparing code) bindings') |
1150 | in gs | 819 | in gs |
1151 | 820 | ||
1152 | isTopKey p@(SecretKeyPacket {}) | not (is_subkey p) = True | ||
1153 | isTopKey p@(PublicKeyPacket {}) | not (is_subkey p) = True | ||
1154 | isTopKey _ = False | ||
1155 | |||
1156 | groupTops ps = groupBy (\_ b -> not (isTopKey b)) ps | ||
1157 | 821 | ||
1158 | 822 | ||
1159 | {- | 823 | {- |