module Ecluse.Core.Package.Integrity (
Strength,
integrityStrength,
assertedAlg,
renderHashAlg,
parseHashAlg,
sriAlgorithm,
sriPrefix,
sriBody,
IntegrityFloor (..),
meetsFloor,
MinIntegrity,
defaultMinIntegrity,
mkMinIntegrity,
parseMinIntegrity,
unMinIntegrity,
renderMinIntegrity,
MinTrustedIntegrity,
defaultMinTrustedIntegrity,
mkMinTrustedIntegrity,
parseMinTrustedIntegrity,
unMinTrustedIntegrity,
renderMinTrustedIntegrity,
VersionIntegrity (..),
classifyArtifacts,
) where
import Ecluse.Core.Package (
Artifact (artHashes),
Hash,
HashAlg (Blake2b, MD5, SHA1, SHA256, SHA384, SHA512, SRI),
hashAlg,
hashValue,
parseHashAlg,
renderHashAlg,
sriAlgorithm,
sriBody,
sriPrefix,
)
data Strength
=
Unasserted
|
Weakest
|
Weak
|
Floor
|
Strong
|
Strongest
deriving stock (Strength -> Strength -> Bool
(Strength -> Strength -> Bool)
-> (Strength -> Strength -> Bool) -> Eq Strength
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Strength -> Strength -> Bool
== :: Strength -> Strength -> Bool
$c/= :: Strength -> Strength -> Bool
/= :: Strength -> Strength -> Bool
Eq, Eq Strength
Eq Strength =>
(Strength -> Strength -> Ordering)
-> (Strength -> Strength -> Bool)
-> (Strength -> Strength -> Bool)
-> (Strength -> Strength -> Bool)
-> (Strength -> Strength -> Bool)
-> (Strength -> Strength -> Strength)
-> (Strength -> Strength -> Strength)
-> Ord Strength
Strength -> Strength -> Bool
Strength -> Strength -> Ordering
Strength -> Strength -> Strength
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Strength -> Strength -> Ordering
compare :: Strength -> Strength -> Ordering
$c< :: Strength -> Strength -> Bool
< :: Strength -> Strength -> Bool
$c<= :: Strength -> Strength -> Bool
<= :: Strength -> Strength -> Bool
$c> :: Strength -> Strength -> Bool
> :: Strength -> Strength -> Bool
$c>= :: Strength -> Strength -> Bool
>= :: Strength -> Strength -> Bool
$cmax :: Strength -> Strength -> Strength
max :: Strength -> Strength -> Strength
$cmin :: Strength -> Strength -> Strength
min :: Strength -> Strength -> Strength
Ord, Int -> Strength -> ShowS
[Strength] -> ShowS
Strength -> String
(Int -> Strength -> ShowS)
-> (Strength -> String) -> ([Strength] -> ShowS) -> Show Strength
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Strength -> ShowS
showsPrec :: Int -> Strength -> ShowS
$cshow :: Strength -> String
show :: Strength -> String
$cshowList :: [Strength] -> ShowS
showList :: [Strength] -> ShowS
Show)
integrityStrength :: HashAlg -> Strength
integrityStrength :: HashAlg -> Strength
integrityStrength = \case
HashAlg
SRI -> Strength
Unasserted
HashAlg
MD5 -> Strength
Weakest
HashAlg
SHA1 -> Strength
Weak
HashAlg
SHA256 -> Strength
Floor
HashAlg
SHA384 -> Strength
Strong
HashAlg
SHA512 -> Strength
Strongest
HashAlg
Blake2b -> Strength
Strongest
assertedAlg :: Hash -> Maybe HashAlg
assertedAlg :: Hash -> Maybe HashAlg
assertedAlg Hash
h = case Hash -> HashAlg
hashAlg Hash
h of
HashAlg
SRI -> Text -> Maybe HashAlg
sriAlgorithm (Hash -> Text
hashValue Hash
h)
HashAlg
alg -> HashAlg -> Maybe HashAlg
forall a. a -> Maybe a
Just HashAlg
alg
class IntegrityFloor floor where
floorAlgorithm :: floor -> HashAlg
newtype MinIntegrity = MinIntegrity HashAlg
deriving stock (MinIntegrity -> MinIntegrity -> Bool
(MinIntegrity -> MinIntegrity -> Bool)
-> (MinIntegrity -> MinIntegrity -> Bool) -> Eq MinIntegrity
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MinIntegrity -> MinIntegrity -> Bool
== :: MinIntegrity -> MinIntegrity -> Bool
$c/= :: MinIntegrity -> MinIntegrity -> Bool
/= :: MinIntegrity -> MinIntegrity -> Bool
Eq, Int -> MinIntegrity -> ShowS
[MinIntegrity] -> ShowS
MinIntegrity -> String
(Int -> MinIntegrity -> ShowS)
-> (MinIntegrity -> String)
-> ([MinIntegrity] -> ShowS)
-> Show MinIntegrity
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MinIntegrity -> ShowS
showsPrec :: Int -> MinIntegrity -> ShowS
$cshow :: MinIntegrity -> String
show :: MinIntegrity -> String
$cshowList :: [MinIntegrity] -> ShowS
showList :: [MinIntegrity] -> ShowS
Show)
defaultMinIntegrity :: MinIntegrity
defaultMinIntegrity :: MinIntegrity
defaultMinIntegrity = HashAlg -> MinIntegrity
MinIntegrity HashAlg
SHA256
mkMinIntegrity :: HashAlg -> Either Text MinIntegrity
mkMinIntegrity :: HashAlg -> Either Text MinIntegrity
mkMinIntegrity HashAlg
alg
| HashAlg -> Strength
integrityStrength HashAlg
alg Strength -> Strength -> Bool
forall a. Ord a => a -> a -> Bool
>= HashAlg -> Strength
integrityStrength HashAlg
SHA256 = MinIntegrity -> Either Text MinIntegrity
forall a b. b -> Either a b
Right (HashAlg -> MinIntegrity
MinIntegrity HashAlg
alg)
| Bool
otherwise =
Text -> Either Text MinIntegrity
forall a b. a -> Either a b
Left
( Text
"the minimum public integrity algorithm must be SHA-256 or stronger, not "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> HashAlg -> Text
renderHashAlg HashAlg
alg
)
parseMinIntegrity :: Text -> Either Text MinIntegrity
parseMinIntegrity :: Text -> Either Text MinIntegrity
parseMinIntegrity Text
raw = Text -> Either Text HashAlg
parseHashAlg Text
raw Either Text HashAlg
-> (HashAlg -> Either Text MinIntegrity)
-> Either Text MinIntegrity
forall a b. Either Text a -> (a -> Either Text b) -> Either Text b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HashAlg -> Either Text MinIntegrity
mkMinIntegrity
unMinIntegrity :: MinIntegrity -> HashAlg
unMinIntegrity :: MinIntegrity -> HashAlg
unMinIntegrity (MinIntegrity HashAlg
alg) = HashAlg
alg
renderMinIntegrity :: MinIntegrity -> Text
renderMinIntegrity :: MinIntegrity -> Text
renderMinIntegrity = HashAlg -> Text
renderHashAlg (HashAlg -> Text)
-> (MinIntegrity -> HashAlg) -> MinIntegrity -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MinIntegrity -> HashAlg
unMinIntegrity
instance IntegrityFloor MinIntegrity where
floorAlgorithm :: MinIntegrity -> HashAlg
floorAlgorithm = MinIntegrity -> HashAlg
unMinIntegrity
newtype MinTrustedIntegrity = MinTrustedIntegrity HashAlg
deriving stock (MinTrustedIntegrity -> MinTrustedIntegrity -> Bool
(MinTrustedIntegrity -> MinTrustedIntegrity -> Bool)
-> (MinTrustedIntegrity -> MinTrustedIntegrity -> Bool)
-> Eq MinTrustedIntegrity
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MinTrustedIntegrity -> MinTrustedIntegrity -> Bool
== :: MinTrustedIntegrity -> MinTrustedIntegrity -> Bool
$c/= :: MinTrustedIntegrity -> MinTrustedIntegrity -> Bool
/= :: MinTrustedIntegrity -> MinTrustedIntegrity -> Bool
Eq, Int -> MinTrustedIntegrity -> ShowS
[MinTrustedIntegrity] -> ShowS
MinTrustedIntegrity -> String
(Int -> MinTrustedIntegrity -> ShowS)
-> (MinTrustedIntegrity -> String)
-> ([MinTrustedIntegrity] -> ShowS)
-> Show MinTrustedIntegrity
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MinTrustedIntegrity -> ShowS
showsPrec :: Int -> MinTrustedIntegrity -> ShowS
$cshow :: MinTrustedIntegrity -> String
show :: MinTrustedIntegrity -> String
$cshowList :: [MinTrustedIntegrity] -> ShowS
showList :: [MinTrustedIntegrity] -> ShowS
Show)
defaultMinTrustedIntegrity :: MinTrustedIntegrity
defaultMinTrustedIntegrity :: MinTrustedIntegrity
defaultMinTrustedIntegrity = HashAlg -> MinTrustedIntegrity
MinTrustedIntegrity HashAlg
SHA256
mkMinTrustedIntegrity :: HashAlg -> Either Text MinTrustedIntegrity
mkMinTrustedIntegrity :: HashAlg -> Either Text MinTrustedIntegrity
mkMinTrustedIntegrity HashAlg
SRI =
Text -> Either Text MinTrustedIntegrity
forall a b. a -> Either a b
Left Text
"the minimum trusted integrity algorithm must name a concrete algorithm, not a bare SRI"
mkMinTrustedIntegrity HashAlg
alg = MinTrustedIntegrity -> Either Text MinTrustedIntegrity
forall a b. b -> Either a b
Right (HashAlg -> MinTrustedIntegrity
MinTrustedIntegrity HashAlg
alg)
parseMinTrustedIntegrity :: Text -> Either Text MinTrustedIntegrity
parseMinTrustedIntegrity :: Text -> Either Text MinTrustedIntegrity
parseMinTrustedIntegrity Text
raw = Text -> Either Text HashAlg
parseHashAlg Text
raw Either Text HashAlg
-> (HashAlg -> Either Text MinTrustedIntegrity)
-> Either Text MinTrustedIntegrity
forall a b. Either Text a -> (a -> Either Text b) -> Either Text b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HashAlg -> Either Text MinTrustedIntegrity
mkMinTrustedIntegrity
unMinTrustedIntegrity :: MinTrustedIntegrity -> HashAlg
unMinTrustedIntegrity :: MinTrustedIntegrity -> HashAlg
unMinTrustedIntegrity (MinTrustedIntegrity HashAlg
alg) = HashAlg
alg
renderMinTrustedIntegrity :: MinTrustedIntegrity -> Text
renderMinTrustedIntegrity :: MinTrustedIntegrity -> Text
renderMinTrustedIntegrity = HashAlg -> Text
renderHashAlg (HashAlg -> Text)
-> (MinTrustedIntegrity -> HashAlg) -> MinTrustedIntegrity -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MinTrustedIntegrity -> HashAlg
unMinTrustedIntegrity
instance IntegrityFloor MinTrustedIntegrity where
floorAlgorithm :: MinTrustedIntegrity -> HashAlg
floorAlgorithm = MinTrustedIntegrity -> HashAlg
unMinTrustedIntegrity
meetsFloor :: (IntegrityFloor floor) => floor -> HashAlg -> Bool
meetsFloor :: forall floor. IntegrityFloor floor => floor -> HashAlg -> Bool
meetsFloor floor
flr HashAlg
alg = HashAlg -> Strength
integrityStrength HashAlg
alg Strength -> Strength -> Bool
forall a. Ord a => a -> a -> Bool
>= HashAlg -> Strength
integrityStrength (floor -> HashAlg
forall floor. IntegrityFloor floor => floor -> HashAlg
floorAlgorithm floor
flr)
data VersionIntegrity
=
MeetsFloor
|
BelowFloor
|
NoIntegrity
deriving stock (VersionIntegrity -> VersionIntegrity -> Bool
(VersionIntegrity -> VersionIntegrity -> Bool)
-> (VersionIntegrity -> VersionIntegrity -> Bool)
-> Eq VersionIntegrity
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: VersionIntegrity -> VersionIntegrity -> Bool
== :: VersionIntegrity -> VersionIntegrity -> Bool
$c/= :: VersionIntegrity -> VersionIntegrity -> Bool
/= :: VersionIntegrity -> VersionIntegrity -> Bool
Eq, Int -> VersionIntegrity -> ShowS
[VersionIntegrity] -> ShowS
VersionIntegrity -> String
(Int -> VersionIntegrity -> ShowS)
-> (VersionIntegrity -> String)
-> ([VersionIntegrity] -> ShowS)
-> Show VersionIntegrity
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> VersionIntegrity -> ShowS
showsPrec :: Int -> VersionIntegrity -> ShowS
$cshow :: VersionIntegrity -> String
show :: VersionIntegrity -> String
$cshowList :: [VersionIntegrity] -> ShowS
showList :: [VersionIntegrity] -> ShowS
Show)
classifyArtifacts :: (IntegrityFloor floor) => floor -> NonEmpty Artifact -> VersionIntegrity
classifyArtifacts :: forall floor.
IntegrityFloor floor =>
floor -> NonEmpty Artifact -> VersionIntegrity
classifyArtifacts floor
flr NonEmpty Artifact
arts
| (Artifact -> Bool) -> NonEmpty Artifact -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Artifact -> Bool
meetsFloorArtifact NonEmpty Artifact
arts = VersionIntegrity
MeetsFloor
| (Artifact -> Bool) -> NonEmpty Artifact -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all ([Hash] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Hash] -> Bool) -> (Artifact -> [Hash]) -> Artifact -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Artifact -> [Hash]
artHashes) NonEmpty Artifact
arts = VersionIntegrity
NoIntegrity
| Bool
otherwise = VersionIntegrity
BelowFloor
where
meetsFloorArtifact :: Artifact -> Bool
meetsFloorArtifact Artifact
art = (Hash -> Bool) -> [Hash] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Hash -> Bool
hashMeetsFloor (Artifact -> [Hash]
artHashes Artifact
art)
hashMeetsFloor :: Hash -> Bool
hashMeetsFloor Hash
h = Bool -> (HashAlg -> Bool) -> Maybe HashAlg -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (floor -> HashAlg -> Bool
forall floor. IntegrityFloor floor => floor -> HashAlg -> Bool
meetsFloor floor
flr) (Hash -> Maybe HashAlg
assertedAlg Hash
h)