2      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                                                                           &None !"*+-12346=BEHJKLM      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~None !"*+-12346=>BEHJKM 1Wrap an action that may throw a checked exceptionThis is used internally in 6 to avoid impredicative instantiation of the type of 'coerce'/'unsafeCoerce'. Checked exceptionsThrow a checked exceptionCatch a checked exception with the arguments reversedLike try, but for checked exceptions+Rethrow IO exceptions as checked exceptionsThrow an unchecked exceptionThis is just an alias for throwV, but makes it evident that this is a very intentional use of an unchecked exception. Variation on  for internal errors    None !"*+-12346=BEHJKMProduce a human-readable stringNone !"*+-12346=BEHJKMNone !"*+-12346=BEHJKM Abstract over a file system rootsee ?#?A file system root can be interpreted as an (absolute) FilePath'PathsA path consists of an optional root and a list of fragments. Alternatively, think of it as a list with two kinds of nil-constructors.( Rooted pathsThe a" parameter is a phantom argument; ( is effectively a proxy.*Unrooted paths:Unrooted paths need a root before they can be interpreted.+Path fragmentsEPath fragments must be non-empty and not contain any path delimiters./For convenience: combine . and -4This can therefore throw the same runtime errors as -.4Reinterpret the root of a pathCOpen a file in read modeWe don't wrap the general withFile$ to encourage using atomic file ops.DWrapper around (openBinaryTempFileWithDefaultPermissionsL,Return the immediate children of a directory Filters out "." and "..".M(Recursive traverse a directory structureReturns a set of paths relative to the directory specified. TODO: Not sure about the memory behaviour with large file systems. Split a path into its componentsUnlike , this satisfies the invariants required by -<. That is, the fragments do NOT contain any path separators.Multiple consecutive path separators are considered to be the same as a single path separator, and leading and trailing separators are ignored.(Turn a path into a human-readable stringO !"# $%&'   ()*+ ,-./0123456789:;<=>?@ABCDEFGHIJKLMNOldNewOPQ Path of the .tar fileBase directory&Files to add, relative to the base dirRSI  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSJ+,-,'*()$%&./0123456789:;<=#"! >?@ABDCEFGIHOLMKJNPQRS F !"# $%&'   ()*+ ,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSNone !"*+-12346=BEHJKMT#Create a short-lived temporary fileKCreates the directory where the temp file should live if it does not exist.WCopy a file atomically2If both files live in the same directory, we call N.. Otherwise we read the source file and call X (because only when the two files live in the same directory can be sure that the two locations are on the same physical device).XAtomically write a bytestringGWe write to a temporary file in the destination folder and then rename.YGLike 'withFile .. WriteMode', but overwrite the destination atomically.We open a handle to a temporary file in the same directory as the final location, then call the callback, and only when there are no exceptions finally rename the temporary file to the final destination.TTemp directoryTemplateCallbackUVWSource DestinationXSource DestinationYFinal destinationCallbackTUVWXYTUVWXYTUVWXYNone !"*+-12346=BEHJKMZ&Location of the various files we cacheAlthough the generic TUF algorithms do not care how we organize the cache, we nonetheless specity this here because as long as there are tools which access files in the cache directly we need to define the cache layout. See also comments for defaultCacheLayout.\TUF root metadata] TUF timestamp^ TUF snapshot_TUF mirrors list`Uncompressed index tarballa'Index to the uncompressed index tarballb$Compressed index tarball (if cached)dThe cache directorye,Layout of the files within the index tarballgTUF metadata for a packagehPackage .cabal filei/Paths relative to the root of the index tarballjThe root of the index tarballkLayout of a repositorymTUF root metadatan TUF timestampo TUF snapshotpTUF mirrors listqCompressed index tarballrUncompressed index tarballsPath to the package tarballtLayout of the indexrSince the repository hosts the index, the layout of the index is not independent of the layout of the repository.u,Paths relative to the root of the repositoryvThe root of the repositoryFRepository roots can be anchored at a remote URL or a local directory. Note that even for remote repos v" is (potentially) different from & -- for a repository located at, say,  http://hackage.haskell.org4 they happen to coincide, but for one location at  $http://example.com/some/subdirectory they do not.wThe layout used on Hackagex/Layout used by cabal for ("legacy") local reposvObviously, such repos do not normally contain any of the TUF files, so their location is more or less arbitrary here.{0The layout of the index as maintained on Hackage|#The cache layout cabal-install usesWe cache the index as  cache /00-index.tar; this is important because `cabal-install`x expects to find it there (and does not currently go through the hackage-security library to get files from the index).}0Anchor a cache path to the location of the cache'Z[\]^_`abcdefghijklmnopqrstuvwxyz{|}$Z[\]^_`abcdefghijklmnopqrstuvwxyz{|}Z[\]^_`abcdefghijk lmnopqrstuvwxyz{|}.(c) Galois, Inc. 2007-2009, Duncan Coutts 2015None !"*+-12346=BEHJKM~ !"#$%&'()* ~ ~~ !"#$%&'()*None !"*+-12346=BEHJKM+Monads in which we can report schema errors Used in the  instance for + Used in the  instance for +"Extract a field from a JSON object&,-./0123456789:;<=>?@~!,-./0123456789:;<=>?@None !"*+-12346=BEHJKMMonomorphic lensPolymorphic lensNone !"*+-12346=BEHJKMACast from one type to anotherUBy default (for language with type inference) we just compare the types returned by B; however, in languages in which terms can have more than one type this may not be the correct definition (indeed, for such languages we cannot give an instance of C).C&Embedded languages with type inferenceD9Equality check that gives us a type-level equality proof.EType equality proofsThis is a direct copy of "type-equality:Data.Type.Equality"; if we don't mind the dependency we can use that package directly. AFCBDGHEI AFCBDGHEIAFCBDGHEINone !"*+-12346=BEHJKMJHasFormat fs f is a proof that f is a key in fs.See K and L for typical usage.MAvailable formatsRather than having a general list here, we enumerate all possibilities. This means we are very precise about what we expect, and we avoid any runtime errors about unexpect format definitions.ZNOTE: If we add additional cases here (for dealing with additional formats) all calls to error "inaccessible" need to be reevaluated.N:Format is a singleton type (reflection type to term level)=NOTE: In the future we might add further compression formats.JOPMQRSTNUVWXYZ[KL\]JOPMQRSTNUVWXYZ[KL JPOMTSRQNVUWXYZ[KL\] None !"*+-12346=BEHJKMType f satisfies  SomeShow f if f a satisfies Show independent of aType f satisfies SomeEq f if f a satisfies Eq independent of a ^_ ^_None !"*+-12346=BEHJKM`^Simple wrapper around bytestring with ToJSON and FromJSON instances that use base64 encoding.`abcde`bc`abcdeNone !"*+-12346=BEHJKMCompute the key ID of a keyThe key ID of a key, by definition, is the hexdigest of the SHA-256 hash of the canonical JSON form of the key where the private object key is excluded.dNOTE: The FromJSON and ToJSON instances for KeyId are ntentially omitted. Use writeKeyAsId instead.*Sign a bytestring and return the signatureSTODO: It is unfortunate that we have to convert to a strict bytestring for ed255193fghijklmnopqrstuvwxyz{|}~,fghijklmnopqrstuvwxyz{|}~ None !"*+-12346=BEHJKMFA key environment is a mapping from key IDs to the corresponding keys.QIt should satisfy the invariant that these key IDs actually match the keys; see .7Verify that each key ID is mapped to a key with that ID  None !"*+-12346=BEHJKM7MonadReader-like monad, specialized to key environmentsWrong file type"Records actual and expected types.Some verification step failed1The JSON file contains a key ID of an unknown key3Invalid JSON has valid syntax but invalid structure6The string gives a hint about what we expected insteadaMalformed JSON has syntax errors in the JSON itself (i.e., we cannot even parse it to a JSValue)Render to canonical JSON format Variation on - for files that don't require the repo layout4:~:~%None !"*+-12346=BEHJKM File hash Key thresholdqThe key threshold is the minimum number of keys a document must be signed with. Key thresholds are specified in RoleSpec or DelegationsSpec. File lengthgHaving verified file length information means we can protect against endless data attacks and similar.  None !"*+-12346=BEHJKMFile information$This intentionally does not have an * instance; see  and verifyFileInfo instead.[NOTE: Throughout we compute file information always over the raw bytes. For example, when timestamp.json lists the hash of  snapshot.json), this hash is computed over the actual  snapshot.json file (as opposed to the canonical form of the embedded JSON). This brings it in line with the hash computed over target files, where that is the only choice available.Compute TODO: Currently this will load the entire input bytestring into memory. We need to make this incremental, by computing the length and all hashes in a single traversal over the input.Compute Compare known file infoThis should be used only when the FileInfo is already known. If we want to compare known FileInfo against a file on disk we should delay until we know have confirmed that the file lengths don't match (see verifyFileInfo).    None !"*+-12346=BEHJKMFile got deleted7File got added or modified; we record the new file info Entries in . either talk about the repository or the indexMapping from paths to file infoxFile maps are used in target files; the paths are relative to the location of the target files containing the file map.OldNewNone !"*+-12346=BEHJKM =Occassionally it is useful to read only a header from a file. HeaderOnly intentionally only has a  instance (no ). File expiry dateA P& value here means no expiry. That makes it possible to set some files to never expire. (Note that not having the Maybe in the type here still allows that, because you could set an expiry date 2000 years into the future. By having the Maybe here we avoid the _need_ for such encoding issues.) File version[The file version is a flat integer which must monotonically increase on every file update.6 and 21 instance are defined in terms of the underlying <A (this is use for example by hackage during the backup process).File expiry date/File version (monotonically increasing counter)               None !"*+-12346=BEHJKM"Types for pattern and replacements1We intentially are not very precise here, saying String (instead of FileName, BaseName, or  Directoryi, say) so that we can, for example, use a matched filename in a pattern as a directory in a replacement. A delegation6A delegation is a pair of a pattern and a replacement.See  for an example.Replacement patterns%These constructors match the ones in !: wildcards must be used in the same order as they appear in the pattern, but they don't all have to be used (that's why the base constructors are polymorphic in the stack tail).!Structured patterns over pathsxThe type argument indicates what kind of function we expect when the pattern matches. For example, we have the pattern  "*/*.txt": \PathPatternDirAny (PathPatternFileExt ".txt") :: PathPattern (Directory :- BaseName :- ())TODOs (see README.md):Update this to work with Path rather than 'FilePath'/'String' Add different kinds of wildcardsAdd path rootsCurrently this is a proof of concept more than anything else; the right structure is here, but it needs updating. However, until we add author signing (or out-of-tarball targets) we don't actually use this yet.LNOTE: Haddock lacks GADT support so constructors have only regular comments.+?The identity replacement replaces a matched pattern with itselfParse a patternParse a replacement\We cheat and use the parser for patterns and then translate using the identity replacement..AQuasi-quoter for delegations to make them easier to write in code#This allows to write delegations as 9$(qqd "targets/*/*/*.cabal" "targets/*/*/revisions.json")_(The alternative syntax which actually uses a quasi-quoter doesn't work very well because the /** bits confuse CPP: "unterminated comment")0 !"#$%&'()*+,-. !"#$%&'()*+,-.# !&%$#"'()*+,-.None !"*+-12346=BEHJKM /5A signature with a key ID (rather than an actual key)DThis corresponds precisely to the TUF representation of a signature.4"File with uninterpreted signaturesSometimes we want to be able to read a file without interpreting the signatures (that is, resolving the key IDs) or doing any kind of checks on them. One advantage of this is that this allows us to read many file types without any key environment at all, which is sometimes useful.<A list of signaturesuInvariant: each signature must be made with a different key. We enforce this invariant for incoming untrusted data (K:) but not for lists of signatures that we create in code.B,Create a new document without any signaturesCSign a documentD Variation on C" that doesn't need the repo layoutE/Construct signatures for already rendered valueG.General FromJSON instance for signed datatypesWe don't give a general FromJSON instance for Signed because for some datatypes we need to do something special (datatypes where we need to read key environments); for instance, see the "Signed Root" instance.HSignature verificationNOTES: 1. By definition, the signature must be verified against the canonical JSON format. This means we _must_ parse and then pretty print (as we do here) because the document as stored may or may not be in canonical format. 2. However, it is important that we NOT translate from the JSValue to whatever internal datatype we are using and then back to JSValue, because that may not roundtrip: we must allow for additional fields in the JSValue that we ignore (and would therefore lose when we attempt to roundtrip). 3. We verify that all signatures are valid, but we cannot verify (here) that these signatures are signed with the right key, or that we have a sufficient number of signatures. This will be the responsibility of the calling code.I&Convert a pre-signature to a signature9Verifies that the key type matches the advertised method.J"Convert signature to pre-signatureKConvert a list of /s to a list of 8sThis verifies the invariant that all signatures are made with different keys. We do this on the presignatures rather than the signatures so that we can do the check on key IDs, rather than keys (the latter don't have an Ord instance).L6Convert list of pre-signatures to a list of signatures%/0123456789:;<=>?@ABCDEFGHIJKL/0123456789:;<=>?@ABCDEFGHIJKL/0123456789:;<=>?@ABCDEFGHIJKL None !"*+-12346=BEHJKMNFull versus partial mirrorsThe TUF spec explicitly allows for partial mirrors, with the mirrors file specifying (through patterns) what is available from partial mirrors.bFor now we only support full mirrors; if we wanted to add partial mirrors, we would add a second  MirrorPartial9 constructor here with arguments corresponding to TUF's  metacontent and targetscontent fields.PDefinition of a mirrormNOTE: Unlike the TUF specification, we require that all mirrors must have the same format. That is, we omit metapath and  targetspath.Y8Give a human-readable description of a particular mirror(for use in error messages)MNOPQRSTUVWXY MNOPQRSTUVWXY MNOPQRSTUVWXY!None !"*+-12346=BEHJKM^File info for the root metadataWe list this explicitly in the snapshot so that we can check if we need to update the root metadata without first having to download the entire index tarball._!File info for the mirror metadata`Compressed index tarballaUncompressed index tarball.Repositories are not required to provide this.Z[\]^_`aZ[\]^_`a Z[\]^_`a"None !"*+-12346=BEHJKMbDelegation specification"NOTE: This is a close analogue of RoleSpec.g DelegationsMuch like the Root datatype, this must have an invariant that ALL used keys (apart from the global keys, which are in the root key environment) must be listed in i.kTarget metadataMost target files do not need expiry dates because they are not subject to change (and hence attacks like freeze attacks are not a concern).bcdefghijklmnopqbcdefghijklmnopq bcdefghijklmnopq#None !"*+-12346=BEHJKM rstuvrstuvrstuv$None !"*+-12346=BEHJKMwRole specificationJThe phantom type indicates what kind of type this role is meant to verify.The root metadata_NOTE: We must have the invariant that ALL keys (apart from delegation keys) must be listed in >. (Delegation keys satisfy a similar invariant, see Targets.)We give an instance for Signed Root rather than Root because the key environment from the root data is necessary to resolve the explicit sharing in the signatures.wxyz{|}~wxyz{|}~ wxyz{|}~%None !"*+-12346=BEHJKMZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~&None !"*+-12346=BEHJKM<Root metadata updated (as part of the normal update process)$Errors thrown during role validationThe spec stipulates that if a verification error occurs during the check for updates, we must download new root information and start over. However, we limit how often we attempt this.BWe record all verification errors that occurred before we gave up._The file we requested from the server was larger than expected (potential endless data attack)uWe tried to lookup file information about a particular target file, but the information wasn't in the corresponding  targets.json file.File information mismatch2The file version is less than the previous versionThe file is expired6Not enough signatures signed with the appropriate keysTrusted values*Trusted values originate in only two ways:.Anything that is statically known is trusted ()dIf we have "dynamic" data we can trust it once we have verified the the signatures (trustSigned).9NOTE: Trusted is NOT a functor. If it was we could define ZtrustAnything :: a -> Trusted a trustAnything a = fmap (const a) (trustStatic (static ()))tConsequently, it is neither a monad nor a comonad. However, we _can_ apply trusted functions to trusted arguments ().The @ constructor is exported, but any use of it should be verified.Equivalent of &yTrusted isn't quite applicative (no pure, not a functor), but it is somehow Applicative-like: we have the equivalent of &Equivalent of  sequenceAvTrusted isn't quite Traversable (no Functor instance), but it is somehow Traversable-like: we have the equivalent of  sequenceARole verificationNOTE: We throw an error when the version number _decreases_, but allow it to be the same. This is sufficient: the file number is there so that attackers cannot replay old files. It cannot protect against freeze attacks (that's what the expiry date is for), so "replaying" the same file is not a problem. If an attacker changes the contents of the file but not the version number we have an inconsistent situation, but this is not something we need to worry about: in this case the attacker will need to resign the file or otherwise the signature won't match, and if the attacker has compromised the key then he might just as well increase the version number and resign.NOTE 2: We are not actually verifying the signatures _themselves_ here (we did that when we parsed the JSON). We are merely verifying the provenance of the keys. Variation on  verifyRole# that uses key IDs rather than keys*This is used during the bootstrap process.See  3http://en.wikipedia.org/wiki/Public_key_fingerprint.!For signature validation File source (for error messages)Previous version (if available)Time now (if checking expiry)For error messages          'None !"*+-12346=BEHJKM-Apply a static function to a trusted argumentVerify We compare file lengths before computing hashes, but once we have verified that the file lengths match we compute _all_ hashes, and then compare the resulting sets. This is the right thing to do: sure, in the case where the file info does _not_ match this is a waste of effort. However, we expect that in the majority of cases the file info _will_ match, in which case having to traverse the file multiple times to compute each hash, rather than traversing the file once and computing all hashes at once, is inefficient.I(Of course, right now the difference is moot since we only use one hash.) Variation on  for    Root dataSource (for error messages)Previous version (if available)Time now (if checking expiry)Mirrors to verify  None !"*+-12346=BEHJKM-#Is a particular remote file cached?VThe index is somewhat special: it should be cached, but we never ask for it directly.2Instead, we will ask the Repository for files _from_ the index, which it can serve however it likes. For instance, some repositories might keep the index in uncompressed form, others in compressed form; some might keep an index tarball index for quick access, others may scan the tarball linearly, etc.We don't cache this remote fileThis doesn't mean a Repository should not feel free to cache the file if desired, but it does mean the generic algorithms will never ask for this file from the cache.<This remote file should be cached, and we ask for it by nameRepository-specific exceptionsFor instance, for repositories using HTTP this might correspond to a 404; for local repositories this might correspond to file-not-found, etc.>Records why we are downloading a file rather than updating it. Update failedaUpdating the local file would actually mean downloading MORE data then doing a regular download.0We don't have a local copy of the file to update-Server does not support incremental downloadsLikewise, it's possible that client _wants_ the compressed form of the file, in which case downloading the uncompressed form is not useful.0Server only provides compressed form of the file Log messages We use a  rather than a u# here because we might not have a u for the file that we were trying to download (that is, for example if the server does not provide an uncompressed tarball, it doesn't make much sense to list the path to that non-existing uncompressed tarball).hWe got an exception with a particular mirror (we will try with a different mirror if any are available)CUpdating a file failed (we will try again by downloading it whole)Selected a particular mirror/Incrementally updating a file from a repository!Download a file from a repositoryA verification errorVerification errors can be temporary, and may be resolved later; hence these are just warnings. (Verification errors that cannot be resolved are thrown as exceptions.)Root information was updatedThis message is issued when the root information is updated as part of the normal check for updates procedure. If the root information is updated because of a verification error WarningVerificationError is issued instead.JAre we requesting this information because of a previous validation error?FClients can take advantage of this to tell caches to revalidate files. Repository4This is an abstract representation of a repository. It simply provides a way to download metafiles and target files, without specifying how this is done. For instance, for a local repository this could just be doing a file read, whereas for remote repositories this could be using any kind of HTTP client.Get a file from the serverResponsibilies of :VDownload the file from the repository and make it available at a temporary locationUse the provided file length to protect against endless data attacks. (Repositories such as local repositories that are not suspectible to endless data attacks can safely ignore this argument.)Move the file from its temporary location to its permanent location if the callback returns successfully (where appropriate).!Responsibilities of the callback:=Verify the file and throw an exception if verification fails.Not modify or move the temporary file. (Thus it is safe for local repositories to directly pass the path into the local repository.)NOTE: Calls to % should _always_ be in the scope of . Get a cached file (if available)Get the cached root\This is a separate method only because clients must ALWAYS have root information available.Clear all cached dataIn particular, this should remove the snapshot and the timestamp. It would also be okay, but not required, to delete the index.Get a file from the indexThe use of a strict bytestring here is intentional: it means the Repository is free to keep the index open and just seek the handle for different files. Since we only extract small files, having the entire extracted file in memory is not an issue.Mirror selectionThe purpose of ; is to scope mirror selection. The idea is that if we have )repWithMirror mirrorList $ someCallback5then the repository may pick a mirror before calling  someCallback, catch exceptions thrown by  someCallbackB, and potentially try the callback again with a different mirror.The list of mirrors may be Nothing if we haven't yet downloaded the list of mirrors from the repository, or when our cached list of mirrors is invalid. Of course, if we did download it, then the list of mirrors may still be empty. In this case the repository must fall back to its primary download mechanism.Mirrors as currently defined (in terms of a "base URL") are inherently a HTTP (or related) concept, so in repository implementations such as the local-repo repWithMirrors/ is probably just an identity operation (see  ignoreMirrors). Conversely, HTTP implementations of repositories may have other, out-of-band information (for example, coming from a cabal config file) that they may use to influence mirror selection.LoggingLayout of this repository9Description of the repository (used in the show instance)Path to temporary file*Files that we might request from the indexATODO: We should also provide a way to extract preferred versions info from the tarball. After all, this is a security sensitive, as it might be used for rollback/freeze attacks. Until we have author signing however this is not a strict necessity, as the preferred versions comes from the index which is itself signed.Cabal file for a packagePackage-specific metadata ( targets.json)0Files that we might request from the local cacheMirrors list ( mirrors.json)Snapshot metadata ( snapshot.json)Root metadata ( root.json)Timestamp metadata (timestamp.json)6Abstract definition of files we might have to download[ is parametrized by the type of the formats that we can accept from the remote repository.LNOTE: Haddock lacks GADT support so constructors have only regular comments.!Default format for each file typeFor most file types we don't have a choice; for the index the repository is only required to offer the GZip-compressed format so that is the default.Default file info (see also )Helper function to implement repWithMirrors.+Which remote files should we cache locally?B ::  None !"*+-12346=BEHJKMShould we check expiry dates?No, don't check expiry dates.This should ONLY be used in exceptional circumstances (such as when the main server is down for longer than the expiry dates used in the timestamp files on mirrors).Yes, check expiry dates/Generic logic for checking if there are updates*This implements the logic described in Section 5.1, "The client application", of the TUF spec. It checks which of the server metadata has changed, and downloads all changed metadata to the local cache. (Metadata here refers both to the TUF security metadata as well as the Hackage packge index.)!Update the root metadata`Note that the new root metadata is verified using the old root metadata, and only then trusted.We don't always have root file information available. If we notice during the normal update process that the root information has changed then the snapshot will give us the new file information; but if we need to update the root information due to a verification error we do not.dWe additionally delete the cached cached snapshot and timestamp. This is necessary for two reasons: fIf during the normal update process we notice that the root info was updated (because the hash of  root.json in the new snapshot is different from the old snapshot) we download new root info and start over, without (yet) downloading a (potential) new index. This means it is important that we not overwrite our local cached snapshot, because if we did we would then on the next iteration conclude there were no updates and we would fail to notice that we should have updated the index. However, unless we do something, this means that we would conclude on the next iteration once again that the root info has changed (because the hash in the new shapshot still doesn't match the hash in the cached snapshot), and we would loop until we throw a ] exception. By deleting the local snapshot we basically reset the client to its initial state, and we will not try to download the root info once again. The only downside of this is that we will also re-download the index after every root info change. However, this should be infrequent enough that this isn't an issue. See also  4https://github.com/theupdateframework/tuf/issues/285.!Additionally, deleting the local timestamp and snapshot protects against an attack where an attacker has set the file version of the snapshot or timestamp to MAX_INT, thereby making further updates impossible. (Such an attack would require a timestamp/snapshot key compromise.)3However, we _ONLY_ do this when the root information has actually changed. If we did this unconditionally it would mean that we delete the locally cached timestamp whenever the version on the remote timestamp is invalid, thereby rendering the file version on the timestamp and the snapshot useless. See Khttps://github.com/theupdateframework/tuf/issues/283#issuecomment-115739521"Get all cached info (if any)Download a packageIt is the responsibility of the callback to move the package from its temporary location to a permanent location (if desired). The callback will only be invoked once the chain of trust has been verified.NOTE: Unlike the check for updates, downloading a package never triggers an update of the root information (even if verification of the package fails).Get a cabal file from the indexThis does currently not do any verification (bcause the cabal file comes from the index, and the index itself is verified). Once we introduce author signing this needs to be adapted.DShould be called only once a local index is available (i.e., after ). Throws an C if there is no cabal file for the specified package in the index.:Check if we need to bootstrap (i.e., if we have root info)Bootstrap the chain of trustNew clients might need to obtain a copy of the root metadata. This however represents a chicken-and-egg problem: how can we verify the root metadata we downloaded? The only possibility is to be provided with a set of an out-of-band set of root keys and an appropriate threshold.nClients who provide a threshold of 0 can do an initial "unsafe" update of the root information, if they wish.The downloaded root information will _only_ be verified against the provided keys, and _not_ against previously downloaded root info (if any). It is the responsibility of the client to call * only when this is the desired behaviour.#>Variation on getRemote where we only expect one type of resultHRe-throw all exceptions thrown by the client API as unchecked exceptions$Local files are assumed trustedThere is no point tracking chain of trust for local files because that chain would necessarily have to start at an implicitly trusted (though unverified) file: the root metadata.%Just a simple wrapper around 2Throws a VerificationError if verification failed.8&'()*+,-./0!1"2345#6789$%For error messagesFile to verify:;<=>?@ABCDEFZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     vuklmnopqrstwxyzjiefgh{dcZ[\]^_`ab|}TUVWXPQRSNOMY*)('!&%$#" +,-.{|}~wxyz>?@A<=89:;BCDEFGH4567/0123IKJLZ[\]^_`aklmnopghijbcdefqrstuv'& '()*+,-./0!1"2345#6789$%:;<=>?@ABCDEF None !"*+-12346=BEHJKMAn IOJ action that represents an incoming response body coming from the server.tThe action gets a single chunk of data from the response body, or an empty bytestring if no more data is available.#This definition is copied from the  http-client package.Proxy configurationbAlthough actually setting the proxy is the purview of the initialization function for individual P implementations and therefore outside the scope of this module, we offer this ProxyConfiguration? type here as a way to uniformly configure proxies across all s.Use automatic proxy settings"What precisely automatic means is < specific, though typically it will involve looking at the  HTTP_PROXY1 environment variable or the (Windows) registry.Use this specific proxyDIndividual HTTP backends use their own types for specifying proxies.Don't use a proxyResponse headersSince different libraries represent headers differently, here we just abstract over the few response headers that we might want to know about..Original server response was compressed (the  however must do decompression)$Server accepts byte-range requests (Accept-Ranges: bytes)Additional request headersSince different libraries represent headers differently, here we just abstract over the few request headers that we might want to setRequest transport compression (Accept-Encoding: gzip) It is the responsibility of the Y to do compression (and report whether the original server reply was compressed or not).NOTE: Clients should NOT allow for compression unless explicitly requested (since decompression happens before signature verification, it is a potential security concern).Set Cache-Control: no-transformSet Cache-Control: max-age=0Abstraction over HTTP clientsThis avoids insisting on a particular implementation (such as the HTTP package) and allows for other implementations (such as a conduit based one).5NOTE: Library-specific exceptions MUST be wrapped in .Download a fileDownload a byte range6Range is starting and (exclusive) end offset in bytes. Construct a Body reader from a lazy bytestringLThis is appropriate if the lazy bytestring is constructed, say, by calling  hGetContents on a network socket, and the chunks of the bytestring correspond to the chunks as they are returned from the OS network layer.LIf the lazy bytestring needs to be re-chunked this function is NOT suitable.None !"*+-12346=BEHJKM&Location and layout of the local cache)Cache a previously downloaded remote fileGRebuild the tarball indexTODO: Should we attempt to rebuild this incrementally? TODO: Use throwChecked rather than throwUnchecked, and deal with the fallout. See  8https://github.com/well-typed/hackage-security/issues/84. Get a cached file (if available)#Get the cached index (if available)Get the cached rootCalling c without root info available is a programmer error and will result in an unchecked exception. See requiresBootstrap.Get a file from the index*Delete a previously downloaded remote fileGHIJK   GHIJKNone !"*+-12346=BEHJKMLocation of the repositoryoNote that we regard the local repository as immutable; we cache files just like we do for remote repositories.<Initialize the repository (and cleanup resources afterwards)Like a remote repository, a local repository takes a RepoLayout as argument; but where the remote repository interprets this RepoLayout relative to a URL, the local repository interprets it relative to a local directory.0It uses the same cache as the remote repository.LGet a file from the serverLocation of local repositoryLocation of local cacheRepository layoutLoggerCallbackLLNone !"*+-12346=BEHJKMMRemote repository configuration(This is purely for internal convenience.N)Download method (downloading or updating)O,Attempt an (incremental) update of this fileWe record the trailer for the file; that is, the number of bytes (counted from the end of the file) that we should overwrite with the remote file.P9Download this file (we cannot update this file right now)QADownload this file (we never attempt to update this type of file)RWe select a mirror in S (the implementation of ). Outside the scope of S' no mirror is selected, and a call to TP will throw an exception. If this exception is ever thrown its a bug: calls to T (&) should _always_ be in the scope of .,Repository options with a reasonable defaultClients should use defaultRepositoryOpts and override required settings.)Should we allow HTTP content compression?Since content compression happens before signature verification, users who are concerned about potential exploits of the decompression algorithm may prefer to disallow content compression.-Do we want to a copy of the compressed index?-This is important for mirroring clients only.Allow additional mirrors?If this is set to True (default), in addition to the (out-of-band) specified mirrors we will also use mirrors reported by those out-of-band mirrors (that is,  mirrors.json).|For some files we might not know the size beforehand, but we might be able to provide an upper bound (timestamp, root info)For most files we download we know the exact size beforehand (because this information comes from the snapshot or delegated info)UBInternal type recording the various server capabilities we supportV'Does the server support range requests?W4Did the server apply content compression previously?fWe use this as a heuristic to decide whether we want to do an incremental update of the index or not.XServer capabilitiesAs the library interacts with the server and receives replies, we may discover more information about the server's capabilities; for instance, we may discover that it supports incremental downloads.Default repository options<Initialize the repository (and cleanup resources afterwards)We allow to specify multiple mirrors to initialize the repository. These are mirrors that can be found "out of band" (out of the scope of the TUF protocol), for example in a  cabal.configS file. The TUF protocol itself will specify that any of these mirrors can serve a  mirrors.jsonq file that itself contains mirrors; we consider these as _additional_ mirrors to the ones that are passed here.aNOTE: The list of mirrors should be non-empty (and should typically include the primary server).TODO: In the future we could allow finer control over precisely which mirrors we use (which combination of the mirrors that are passed as arguments here and the mirrors that we get from  mirrors.json,) as well as indicating mirror preferences.YGet the selected mirrorXThrows an exception if no mirror was selected (this would be a bug in the client code).NOTE: Cannot use Zl here, because the callback would be inside the scope of the withMVar, and there might be further calls to T# made by the callback argument to T, leading to deadlock.TGet a file from the server[DGet a file from the server, assuming we have already picked a mirror\ HTTP optionsWe want to make sure caches don't transform files in any way (as this will mess things up with respect to hashes etc). Additionally, after a validation error we want to make sure caches get files upstream in case the validation error was because the cache updated files out of order.SMirror selection];Download the specified file using the given download method^Execute a body reader(NOTE: This intentially does NOT use the with.. pattern: we want to execute the entire body reader (or cancel it) and write the results to a file and then continue. We do NOT want to scope the remainder of the computation as part of the same HTTP request.&TODO: Deal with minimum download rate._#Extracting or estimating file sizes`"Bound on the size of the timestamp9This is intended as a permissive rather than tight bound. The timestamp signed with a single key is 420 bytes; the signature makes up just under 200 bytes of that. So even if the timestamp is signed with 10 keys it would still only be 2420 bytes. Doubling this amount, an upper bound of 4kB should definitely be sufficient.aBound on the size of the root9This is intended as a permissive rather than tight bound.+The variable parts of the root metadata are-Signatures, each of which are about 200 bytesdA key environment (mapping from key IDs to public keys), each is of which is also about 200 bytesMirrors, root, snapshot, targets, and timestamp role specifications. These contains key IDs, each of which is about 80 bytes.9A skeleton root metadata is about 580 bytes. Allowing for100 signatures[100 mirror keys, 1000 root keys, 100 snapshot keys, 1000 target keys, 100 timestamp keys5the corresponding 2300 entries in the key environment|We end up with a bound of about 665,000 bytes. Doubling this amount, an upper bound of 2MB should definitely be sufficient.b7Template for the local file we use to download a URI tocMultiple exit points#We can simulate the imperative code Zif (cond1) return exp1; if (cond2) return exp2; if (cond3) return exp3; return exp4;as rchoose $ do when (cond1) $ exit exp1 when (cond) $ exit exp2 when (cond) exit exp3 return exp4dFunction exit point (see c)8MefghijklNOmnopPqQrRUsVWXtuvw#Implementation of the HTTP protocol"Out of band" list of mirrorsRepository optionsLocation of local cacheRepository layoutLoggerCallbackYT[\S HTTP client MVar indicating currently mirrorLoggerOut-of-band mirrorsRepository options TUF mirrorsCallbackx]Internal configuration%Did a security check previously fail? File to getCallbackSelected format^!File source (for error msgs only)Maximum file sizeHandle to write data too*The action to give us blocks from the filey_`abzcd  MefghijklN QPOrrqmnopRUsVWXtuvwYT[\Sx]^y_`abzcd(None !"*+-12346=BEHJKMZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     vuklmnopqrstwxyzjiefgh{dcZ[\]^_`ab|}TUVWXPQRSNOMY*)('!&%$#" +,-.{|}~wxyz>?@A<=89:;BCDEFGH4567/0123IKJLZ[\]^_`aklmnopghijbcdefqrstuv{)*+),-),.),/)01)02)03)04)05)*6)*7)*8)*9:;<=>?@ABCDEFGHIIJKLMNOPQRSTTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                       ! " # $%%&'(())*+,-./01223456789:;<=>?@ABCDEFGGHIJKKLMNNOPQQRRSTUVWXYZ[\]^_ ` a b c c d e f f g h i j!k!k!l!m!n!o!p!q"r"r"s"t"u"v"v"w"x"y"y"z"{"|"}"~#####$$$$$$$$$$$$$$$$$&&&&&&&&                                                                           )))  )  )  ) ))))))))))))) )!"#"$)%)&)')()))*)+),)-).)/0)/1)2)3"4)56)7)8)9):);"<)=>)?)5@)A)BC)/DEFEGEHEIEJKLMEN)OEP)QR)SETEU)QV)QWEXEYEZ)[\)])^_)`a) b)c)^d)ef)gh)/i)/j)kl)m)n)o)p)q)r)s)t)u)v)w)x)yz){|){}){~){){){){){){)y)y)`)[)[)[)Q)=)=)=)=)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5)5))))))))))))))))))))))))))B)B)B)B)B)B)B)B)))))) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )^)^)))))))))))))) " " " " """"""V !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopq r sttuvwxyz{|}~     !      y{|}      !!!!!!!!""""""""#####$$$$$$$&&&&&&&&&&&&&&& & & & & & &&&&&''''''''''     ! " # $%&'()**+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQR9LSTUVW)XYZ[\]^_`abcMdefghijklmnopVqrstuvwxhackage-security-0.2.0.0Hackage.Security.Util.PathHackage.Security.Util.CheckedHackage.Security.Util.PrettyHackage.Security.Util.IOHackage.Security.ClientText.JSON.CanonicalHackage.Security.JSONHackage.Security.Util.LensHackage.Security.Util.SomeHackage.Security.Key.EnvHackage.Security.TUF.FileMap"Hackage.Security.Client.Repository*Hackage.Security.Client.Repository.HttpLib(Hackage.Security.Client.Repository.Cache(Hackage.Security.Client.Repository.Local)Hackage.Security.Client.Repository.RemotePreludeHackage.Security.Util.StackFilePath splitPathHackage.Security.TUF.LayoutHackage.Security.Util.JSON#Hackage.Security.Util.TypedEmbeddedHackage.Security.Client.FormatsHackage.Security.Util.Base64Hackage.Security.KeyHackage.Security.TUF.CommonHackage.Security.TUF.FileInfoHackage.Security.TUF.HeaderHackage.Security.TUF.PatternsHackage.Security.TUF.SignedHackage.Security.TUF.MirrorsHackage.Security.TUF.SnapshotHackage.Security.TUF.TargetsHackage.Security.TUF.TimestampHackage.Security.TUF.RootHackage.Security.TUFHackage.Security.Trusted.TCBHackage.Security.TrustedHackage.Security.ServerbaseGHC.IO.Handle.TypesHandle GHC.IO.Handle hSetBuffering hFileSizehClose GHC.IO.IOModeReadMode WriteMode AppendMode ReadWriteModeIOMode NoBuffering LineBufferingBlockBuffering BufferModeThrowsunthrow throwChecked catchChecked handleChecked tryCheckedcheckIOthrowUnchecked internalErrorPrettyprettyURIPathWebRoot TarballPath TarballRootFileSystemPath RelativePath AbsolutePathHomeDirAbsoluteRelativeIsFileSystemRoot UnrootedPathIsRootshowRootPathRootedUnrootedFragment unFragment mkFragmentfragment fragment'rootPath unrootPath unrootPath'castRoot joinFragmentssplitFragmentstoUnrootedFilePathfromUnrootedFilePathisPathPrefixOf takeDirectory takeFileName<.>splitExtension toFilePath fromFilePath makeAbsolutetoAbsoluteFilePathfromAbsoluteFilePathwithFileInReadMode openTempFilereadLazyByteStringreadStrictByteStringcreateDirectoryIfMissing doesFileExistdoesDirectoryExist removeFilegetTemporaryDirectorygetDirectoryContentsgetRecursiveContents renameFilegetCurrentDirectorytarIndexLookup tarAppenduriPath modifyUriPath withTempFile getFileSizehandleDoesNotExistatomicCopyFileatomicWriteFileatomicWithFile CacheLayoutcacheLayoutRootcacheLayoutTimestampcacheLayoutSnapshotcacheLayoutMirrorscacheLayoutIndexTarcacheLayoutIndexIdxcacheLayoutIndexTarGz CachePath CacheRoot IndexLayoutindexLayoutPkgMetadataindexLayoutPkgCabal IndexPath IndexRoot RepoLayoutrepoLayoutRootrepoLayoutTimestamprepoLayoutSnapshotrepoLayoutMirrorsrepoLayoutIndexTarGzrepoLayoutIndexTarrepoLayoutPkgTarGzrepoIndexLayoutRepoPathRepoRoothackageRepoLayoutcabalLocalRepoLayoutanchorRepoPathLocallyanchorRepoPathRemotelyhackageIndexLayoutcabalCacheLayoutanchorCachePathJSValueJSObjectJSArrayJSStringJSNumJSBoolJSNullrenderCanonicalJSONparseCanonicalJSONGotExpectedReportSchemaErrorsexpected FromObjectKey fromObjectKey ToObjectKey toObjectKeyFromJSONfromJSONToJSONtoJSON expected' fromJSObject fromJSFieldfromJSOptFieldmkObjectLens'LensgetmodifysetlookupMSomeShowsomeShowDictShowSomeEqsomeEqDictEqSome typecheckSomeHasKeyIdkeyIdKeyId keyIdStringKeyTypeKeyTypeEd25519 PrivateKeyPrivateKeyEd25519 PublicKeyPublicKeyEd25519Key KeyEd25519Ed25519 publicKey privateKey somePublicKeysomePublicKeyType someKeyId createKey createKey'signverifyKeyEnv keyEnvMapfromPublicKeysfromKeysemptynullinsertlookupunion WriteJSONReadJSON_NoKeys_NoLayoutReadJSON_Keys_NoLayoutReadJSON_Keys_Layout MonadKeys localKeysaskKeysDeserializationErrorDeserializationErrorFileTypeDeserializationErrorValidationDeserializationErrorUnknownKeyDeserializationErrorSchemaDeserializationErrorMalformedvalidate verifyType readKeyAsIdaddKeyswithKeys lookupKeyrunReadJSON_Keys_LayoutrunReadJSON_Keys_NoLayoutrunReadJSON_NoKeys_NoLayoutparseJSON_Keys_LayoutparseJSON_Keys_NoLayoutparseJSON_NoKeys_NoLayoutreadJSON_Keys_LayoutreadJSON_Keys_NoLayoutreadJSON_NoKeys_NoLayout runWriteJSON renderJSONrenderJSON_NoLayout writeJSONwriteJSON_NoLayout writeKeyAsIdHash KeyThreshold FileLength fileLengthFileInfofileInfoLengthfileInfoHashesHashFn HashFnSHA256fileInfocomputeFileInfoknownFileInfoEqual FileChange FileDeleted FileChanged TargetPathTargetPathIndexTargetPathRepoFileMap!fromListfileMapChangesHeader headerExpires headerVersion FileExpires FileVersion HasHeader fileExpires fileVersion expiresNever expiresInDays isExpiredversionInitialversionIncrement Delegation Replacement RepDirAny RepDirConst RepFileAny RepFileExt RepFileConstPattern PatDirAny PatDirConst PatFileAny PatFileExt PatFileConstBaseName Extension DirectoryFileNameidentityReplacementmatchDelegationparseDelegationqqd PreSignature presignature presigMethod presigKeyIdUninterpretedSignaturesuninterpretedSigneduninterpretedSignatures Signature signature signatureKey SignaturesSignedsigned signaturesunsignedwithSignatureswithSignatures' signRenderedverifySignaturesignedFromJSONverifySignaturesfromPreSignaturetoPreSignaturefromPreSignaturestoPreSignaturesMirrorDescription MirrorContent MirrorFullMirror mirrorUrlBase mirrorContentMirrorsmirrorsVersionmirrorsExpiresmirrorsMirrorsdescribeMirrorSnapshotsnapshotVersionsnapshotExpiressnapshotInfoRootsnapshotInfoMirrorssnapshotInfoTarGzsnapshotInfoTarDelegationSpecdelegationSpecKeysdelegationSpecThreshold delegation DelegationsdelegationsKeysdelegationsRolesTargetstargetsVersiontargetsExpirestargetsTargetstargetsDelegations targetsLookup TimestamptimestampVersiontimestampExpirestimestampInfoSnapshotRoleSpec roleSpecKeysroleSpecThreshold RootRoles rootRolesRootrootRolesSnapshotrootRolesTargetsrootRolesTimestamprootRolesMirrorsRoot rootVersion rootExpiresrootKeys rootRolesVerificationErrorVerificationErrorLoopVerificationErrorFileTooLargeVerificationErrorUnknownTargetVerificationErrorFileInfoVerificationErrorVersionVerificationErrorExpiredVerificationErrorSignaturesIsCached CacheIndex DontCacheCacheAsSomeRemoteError UpdateFailure UpdateFailedUpdateTooLargeUpdateImpossibleNoLocalCopyUpdateImpossibleUnsupportedUpdateNotUsefulWantsCompressedUpdateImpossibleOnlyCompressed LogMessageLogMirrorFailedLogUpdateFailedLogSelectedMirror LogUpdatingLogDownloadingLogVerificationErrorLogRootUpdatedIsRetryAfterVerificationError FirstAttempt Repository repWithRemote repGetCachedrepGetCachedRoot repClearCacherepGetFromIndex repWithMirrorrepLog repLayoutrepDescriptionTempPath IndexFile IndexPkgCabalIndexPkgMetadata CachedFile CachedMirrorsCachedSnapshot CachedRootCachedTimestamp RemoteFileRemotePkgTarGz RemoteIndex RemoteMirrorsRemoteSnapshot RemoteRootRemoteTimestampremoteFileDefaultFormatremoteFileDefaultInfomirrorsUnsupportedremoteRepoPathremoteRepoPath' indexFilePath mustCacheInvalidFileInIndexLocalFileCorruptedInvalidPackageException HasUpdates NoUpdates CheckExpiryDontCheckExpirycheckForUpdatesdownloadPackage getCabalFilerequiresBootstrap bootstrapuncheckClientErrors BodyReader ProxyConfigProxyConfigAutoProxyConfigUseProxyConfigNoneHttpResponseHeaderHttpResponseContentCompressionHttpResponseAcceptRangesBytesHttpRequestHeaderHttpRequestContentCompressionHttpRequestNoTransformHttpRequestMaxAge0HttpLibhttpGet httpGetRangebodyReaderFromBSCache cacheRoot cacheLayoutcacheRemoteFile getCachedgetCachedIndex getCachedRoot getFromIndex clearCache LocalRepowithRepositoryRepoOptsrepoAllowContentCompressionrepoWantCompressedIndexrepoAllowAdditionalMirrorsFileSize FileSizeBound FileSizeExactfileSizeWithinBoundsdefaultRepoOptsdisplayExceptionGHC.Base++GHC.Errerrorfoldrghc-primGHC.PrimseqGHC.Listconcatfilterzip System.IOprint Data.Tuplefstsnd otherwisemap$ undefinedGHC.Num fromInteger-GHC.Real fromRationalGHC.EnumenumFrom enumFromThen enumFromToenumFromThenTo GHC.Classes==>=negatefail>>=>>fmapreturn fromIntegral realToFrac toInteger toRationalControl.Applicative<*>pureBoundedEnumEq GHC.FloatFloating FractionalIntegralMonadFunctorNumOrdGHC.ReadReadReal RealFloatRealFracGHC.ShowShow Applicative GHC.TypesBoolCharDoubleFloatInt integer-gmpGHC.Integer.TypeIntegerOrderingRationalIO Data.EitherEitherStringFalseTrueLeftRightLTEQGT Data.MonoidmappendreadFile Data.MaybeMaybe Text.ReadreadzipWithGHC.IONothingText.ParserCombinators.ReadPReadSData.Traversabletraverse<**> Data.Functor<$>$!readIOreadLn appendFile writeFileinteract getContentsgetLinegetCharputStrLnputStrputCharGHC.IO.ExceptionioError Data.Listunwordswordsunlineslinesproductsumfoldl1minimummaximum userErrorIOErrorreadsmconcatmemptyMonoideitherlex readParenreadList readsPrecacoshatanhasinhcoshtanhsinhacosatanasincostansinlogBase**logsqrtexppiatan2isIEEEisNegativeZeroisDenormalized isInfiniteisNaN scaleFloat significandexponent encodeFloat decodeFloat floatRange floatDigits floatRadixlcmgcd^^^oddevendivModquotRemmoddivremquotrecip/floorceilingroundtruncateproperFractionmaxBoundminBoundfromEnumtoEnumpredsucc showParen showStringshowCharshowsShowSshowListshow showsPrec Control.MonadmapM_mapM sequence_sequence=<<unzip3unzipzipWith3zip3!! concatMapnotElemelemallanyorandreversebreakspansplitAtdroptake dropWhile takeWhilecycle replicaterepeatiteratescanr1scanrfoldr1scanl1scanlfoldllengthinitlasttailheadmaybeJustuncurrycurrysubtractsignumabs*+asTypeOfuntilflip.constid<$/=compare<=&&||not<>maxminWrapCatchProxyunWrap coerceWrap $fThrowsCatch:- $fPrettyPath interpretRootPathSnocPathNilPathRoot toURIPath fromURIPath $fShowRooted$fIsFileSystemRootHomeDir$fIsFileSystemRootAbsolute$fIsFileSystemRootRelative$fIsRootHomeDir$fIsRootAbsolute$fIsRootRelative $fOrdPath$fEqPath$fPrettyFragment$fIsRootCacheRoot$fIsRootIndexRoot$fIsRootRepoRoots_values_strings_arrays_objectp_valuetokp_jvaluep_null p_booleanp_arrayp_stringp_objectp_numbermanyNcontainers-0.5.5.1 Data.Map.BaseMap unknownField$fFromJSONmURI $fToJSONmURI$fFromJSONmMap $fToJSONmMap$fFromJSONmUTCTime$fToJSONmUTCTime $fFromJSONm[] $fToJSONm[]$fFromJSONmInt $fToJSONmInt$fFromJSONm[]0 $fToJSONm[]0$fFromJSONmJSValue$fToJSONmJSValue$fFromObjectKeymPath$fToObjectKeymPath$fFromObjectKeymPath0$fToObjectKeymPath0$fFromObjectKeym[]$fToObjectKeym[]AsTypetypeOfTypedUnify:=:asTypeunifyTypeOfRefl HasFormat formatsMember formatsLookupFormatsFormatHFSHFZFsUnGzFsGzFsUnFsNoneFGzFUnFormatGzFormatUnhasFormatAbsurd hasFormatGet formatsMap$fFunctorFormats $fUnifyFormat $fShowSome$fEqSomeBase64fromByteString toByteString$fFromJSONmBase64$fToJSONmBase64$fFromJSONmSome$fToJSONmKeyType$fFromJSONmSome0 $fToJSONmSome$fToJSONmSome0$fToJSONmSome1$fToJSONmPublicKey$fFromJSONmSome1 $fToJSONmKey $fHasKeyIdKey$fHasKeyIdPublicKey$fFromObjectKeymKeyId$fToObjectKeymKeyId$fTypedPrivateKey$fTypedPublicKey $fTypedKeyTFCo:R:TypeOfPrivateKeyTFCo:R:TypeOfPublicKeyTFCo:R:TypeOfKey$fUnifyKeyType$fSomeEqKeyType$fSomeShowKeyType$fSomeEqPrivateKey$fSomeEqPublicKey $fSomeEqKey$fSomeShowPrivateKey$fSomeShowPublicKey $fSomeShowKeycheckKeyEnvInvariant$fFromJSONmKeyEnv$fToJSONmKeyEnv unWriteJSONunReadJSON_NoKeys_NoLayoutunReadJSON_Keys_NoLayoutunReadJSON_Keys_Layout expectedError!$fMonadKeysReadJSON_Keys_NoLayout$fMonadKeysReadJSON_Keys_Layout+$fMonadReaderRepoLayoutReadJSON_Keys_Layout,$fReportSchemaErrorsReadJSON_NoKeys_NoLayout*$fReportSchemaErrorsReadJSON_Keys_NoLayout($fReportSchemaErrorsReadJSON_Keys_Layout$fPrettyDeserializationError$fExceptionDeserializationError$fShowDeserializationError$fFromJSONmHash$fFromJSONmFileLength$fFromJSONmKeyThreshold $fToJSONmHash$fToJSONmFileLength$fToJSONmKeyThreshold$fFromJSONmFileInfo$fToJSONmFileInfo$fFromObjectKeymHashFn$fToObjectKeymHashFnfileMap$fFromObjectKeymTargetPath$fToObjectKeymTargetPath$fFromJSONmFileMap$fToJSONmFileMap$fPrettyTargetPathoneDay$fFromJSONmHeader$fFromJSONmFileExpires$fFromJSONmFileVersion$fToJSONmFileExpires$fToJSONmFileVersion$fHasHeaderHeader$fReadFileVersion$fShowFileVersion PatternTypetemplate-haskellLanguage.Haskell.TH.Libmatch parsePatternparseReplacement PatTypeStr PatTypeNil matchPatternconstructReplacement prettyPatternprettyReplacement_ex1_ex2_ex3$fToJSONmReplacement$fToJSONmPattern$fLiftDelegation$fLiftReplacement $fLiftPattern$fAsTypeReplacement$fTypedPatternTFCo:R:TypeOfReplacementTFCo:R:TypeOfPattern$fUnifyPatternType $fToJSONmUninterpretedSignatures"$fFromJSONmUninterpretedSignatures$fToJSONmPreSignature$fFromJSONmPreSignature$fFromJSONmSignatures$fToJSONmSignatures$fToJSONmSigned$fFromJSONmSigned$fFromJSONmMirrors$fFromJSONmMirror$fToJSONmMirrors$fToJSONmMirror$fHasHeaderMirrorspathRoot pathMirrorspathIndexTarGz pathIndexTar$fFromJSONmSnapshot$fToJSONmSnapshot$fHasHeaderSnapshot$fFromJSONmTargets$fToJSONmTargets$fFromJSONmDelegations$fToJSONmDelegations$fFromJSONmDelegationSpec$fToJSONmDelegationSpec$fHasHeaderTargets pathSnapshot$fFromJSONmTimestamp$fToJSONmTimestamp$fHasHeaderTimestamp$fFromJSONmRoleSpec$fToJSONmRoleSpec $fToJSONmRoot$fFromJSONmRootRoles$fToJSONmRootRoles$fHasHeaderRoot RootUpdatedTrusted trustStatic trustApplyDeclareTrustedtrustSeq verifyRole'verifyFingerprintsVerificationHistorySignaturesVerifiedsignaturesVerifiedtrusted StaticPtrdeRefStaticPtrstatic trustVerified$fPrettyRootUpdated$fPrettyVerificationError$fExceptionRootUpdated$fShowRootUpdated$fShowVerificationError$fExceptionVerificationError<$$>verifyFileInfotrustedFileInfoEqual VerifyRole verifyRolelazyAndM$fVerifyRoleMirrors$fVerifyRoleSnapshot$fVerifyRoleTimestamp$fVerifyRoleRoot$fPrettyUpdateFailure$fPrettyLogMessage$fPrettySomeRemoteError$fShowSomeRemoteError$fExceptionSomeRemoteError$fShowRepository$fPrettyIndexFile$fPrettyRemoteFile updateRoot getCachedInfo getRemote'trustLocalFileverifyFileInfo' CachedInfo cachedRoot cachedKeyEnvcachedTimestampcachedSnapshot cachedMirrorscachedInfoSnapshotcachedInfoRootcachedInfoMirrorscachedInfoTarGz cachedVersion readLocalRoot readLocalFile getRemoteFile getRemote withMirrorreadJSONthrowErrorsUncheckedthrowErrorsChecked eitherToMaybe$fPrettyInvalidFileInIndex$fPrettyLocalFileCorrupted$fPrettyInvalidPackageException$fExceptionInvalidFileInIndex$fExceptionLocalFileCorrupted"$fExceptionInvalidPackageException$fShowInvalidFileInIndex$fShowLocalFileCorrupted$fShowInvalidPackageExceptionrebuildTarIndexcachedFilePathcachedIndexTarPathcachedIndexTarGzPathcachedIndexIdxPath withRemote RemoteConfigDownloadMethodUpdate CannotUpdate NeverUpdatedSelectedMirrorServerCapabilities_serverAcceptRangesBytesserverUsedContentCompressionServerCapabilitiesgetSelectedMirrorControl.Concurrent.MVarwithMVar withRemote'httpRequestHeadersgetFileexecBodyReaderremoteFileSizefileSizeBoundTimestampfileSizeBoundRoot uriTemplatemultipleExitPointsexit cfgLayout cfgHttpLibcfgBasecfgCachecfgCaps cfgLoggercfgOpts updateFormat updateInfo updateLocal updateTrailerdownloadReasondownloadFormatSCnewServerCapabilitiesupdateServerCapabilitiescheckServerCapabilitypickDownloadMethod remoteFileURI fileLength'