# updater.py
**updater.py** is intended as the only TUF module that software update
systems need to utilize for a low-level integration.  It provides a single
class representing an updater that includes methods to download, install, and
verify metadata or target files in a secure manner.  Importing
**tuf.client.updater** and instantiating its main class is all that is
required by the client prior to a TUF update request.  The importation and
instantiation steps allow TUF to load all of the required metadata files
and set the repository mirror information.

The **tuf.repository_tool** module can be used to create a TUF repository.  See
[tuf/README](../README.md) for more information on creating TUF repositories.


## Overview of the Update Process

1. The software update system instructs TUF to check for updates.

2. TUF downloads and verifies timestamp.json.

3. If timestamp.json indicates that snapshot.json has changed, TUF downloads and
verifies snapshot.json.

4. TUF determines which metadata files listed in snapshot.json differ from those
described in the last snapshot.json that TUF has seen.  If root.json has changed,
the update process starts over using the new root.json.

5. TUF provides the software update system with a list of available files
according to targets.json.

6. The software update system instructs TUF to download a specific target
file.

7. TUF downloads and verifies the file and then makes the file available to
the software update system.


If at any point in the above procedure there is a problem (i.e., if unexpired,
signed, valid metadata cannot be retrieved from the repository), the Root file
is downloaded and the process is retried once more (and only once to avoid an
infinite loop).  Optionally, the software update system using the framework
can decide how to proceed rather than automatically downloading a new Root file.


## Example Client
### Refresh TUF Metadata
```Python
# The client first imports the 'updater.py' module, the only module the
# client is required to import.  The client will utilize a single class
# from this module.
import tuf.client.updater
import tuf.settings

# The only other module the client interacts with is 'settings'.  The
# client accesses this module solely to set the repository directory.
# This directory will hold the files downloaded from a remote repository.
tuf.settings.repositories_directory = 'path/to/local_repository'

# Next, the client creates a dictionary object containing the repository
# mirrors.  The client may download content from any one of these mirrors.
# In the example below, a single mirror named 'mirror1' is defined.  The
# mirror is located at 'http://localhost:8001', and all of the metadata
# and targets files can be found in the 'metadata' and 'targets' directory,
# respectively.  If the client wishes to only download target files from
# specific directories on the mirror, the 'confined_target_dirs' field
# should be set.  In the example, the client has chosen '', which is
# interpreted as no confinement.  In other words, the client can download
# targets from any directory or subdirectories.  If the client had chosen
# 'targets1/', they would have been confined to the '/targets/targets1/'
# directory on the 'http://localhost:8001' mirror.
repository_mirrors = {'mirror1': {'url_prefix': 'http://localhost:8001',
                                  'metadata_path': 'metadata',
                                  'targets_path': 'targets',
                                  'confined_target_dirs': ['']}}

# The updater may now be instantiated.  The Updater class of 'updater.py'
# is called with two arguments.  The first argument assigns a name to this
# particular updater and the second argument the repository mirrors defined
# above.
updater = tuf.client.updater.Updater('updater', repository_mirrors)

# The client calls the refresh() method to ensure it has the latest
# copies of the top-level metadata files (i.e., Root, Targets, Snapshot,
# Timestamp).
updater.refresh()
```


### Download Specific Target File
```Python
# Example demonstrating an update that downloads a specific target.

# Refresh the metadata of the top-level roles (i.e., Root, Targets, Snapshot, Timestamp).
updater.refresh()

# get_one_valid_targetinfo() updates role metadata when required.  In other
# words, if the client doesn't possess the metadata that lists 'LICENSE.txt',
# get_one_valid_targetinfo() will try to fetch / update it.
target = updater.get_one_valid_targetinfo('LICENSE.txt')
updated_target = updater.updated_targets([target], destination_directory)

for target in updated_target:
  updater.download_target(target, destination_directory)
  # Client code here may also reference target information (including 'custom')
  # by directly accessing the dictionary entries of the target.  The 'custom'
  # entry is additional file information explicitly set by the remote repository.
  target_path = target['filepath']
  target_length = target['fileinfo']['length']
  target_hashes = target['fileinfo']['hashes']
  target_custom_data = target['fileinfo']['custom']

  # Remove any files from the destination directory that are no longer being
  # tracked. For example, a target file from a previous snapshot that has since
  # been removed on the remote repository.
  updater.remove_obsolete_targets(destination_directory)
```

### A Simple Integration Example with client.py
``` Bash
# Assume a simple TUF repository has been setup with 'repo.py'.
$ client.py --repo http://localhost:8001

# Metadata and target files are silently updated.  An exception is only raised if an error,
# or attack, is detected.  Inspect 'tuf.log' for the outcome of the update process.

$ cat tuf.log
[2013-12-16 16:17:05,267 UTC] [tuf.download] [INFO][_download_file:726@download.py]
Downloading: http://localhost:8001/metadata/timestamp.json

[2013-12-16 16:17:05,269 UTC] [tuf.download] [WARNING][_check_content_length:589@download.py]
reported_length (545) < required_length (2048)

[2013-12-16 16:17:05,269 UTC] [tuf.download] [WARNING][_check_downloaded_length:656@download.py]
Downloaded 545 bytes, but expected 2048 bytes. There is a difference of 1503 bytes!

[2013-12-16 16:17:05,611 UTC] [tuf.download] [INFO][_download_file:726@download.py]
Downloading: http://localhost:8001/metadata/snapshot.json

[2013-12-16 16:17:05,612 UTC] [tuf.client.updater] [INFO][_check_hashes:636@updater.py]
The file's sha256 hash is correct: 782675fadd650eeb2926d33c401b5896caacf4fd6766498baf2bce2f3b739db4

[2013-12-16 16:17:05,951 UTC] [tuf.download] [INFO][_download_file:726@download.py]
Downloading: http://localhost:8001/metadata/targets.json

[2013-12-16 16:17:05,952 UTC] [tuf.client.updater] [INFO][_check_hashes:636@updater.py]
The file's sha256 hash is correct: a5019c28a1595c43a14cad2b6252c4d1db472dd6412a9204181ad6d61b1dd69a

[2013-12-16 16:17:06,299 UTC] [tuf.download] [INFO][_download_file:726@download.py]
Downloading: http://localhost:8001/targets/file1.txt

[2013-12-16 16:17:06,303 UTC] [tuf.client.updater] [INFO][_check_hashes:636@updater.py]
The file's sha256 hash is correct: ecdc5536f73bdae8816f0ea40726ef5e9b810d914493075903bb90623d97b1d8
