blob: 75c967de51f07d391fa8904894b4c9a67a781fb3 [file] [log] [blame]
// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package upspin // import "upspin.io/upspin"
import (
"crypto/elliptic"
"errors"
"math/big"
"time"
)
// A UserName is just an e-mail address representing a user.
// It is given a unique type so the API is clear.
// The user part may contain an optional suffix after a plus sign.
// Examples: gopher@google.com, me+you@forever.com
type UserName string
// A PathName is just a string representing a full path name.
// It is given a unique type so the API is clear.
// Example: gopher@google.com/burrow/hoard
type PathName string
// Transport identifies the type of access required to reach the data, that is, the
// realm in which the network address within a Location is to be interpreted.
type Transport uint8
const (
// Unassigned denotes a connection to a service that returns an error
// from every method call. It is useful when a component wants to
// guarantee it does not access another service.
// It is also the zero value for Transport.
Unassigned Transport = iota
// InProcess denotes that contents are located in the current process,
// typically in memory.
InProcess
// Remote denotes a connection to a remote server through RPC.
// (Although called remote, the service may be running on the same machine.)
// The Endpoint's NetAddr contains the HTTP address of the server.
Remote
)
// A Location identifies where a piece of data is stored and how to retrieve it.
type Location struct {
// Endpoint identifies the machine or service where the data resides.
Endpoint Endpoint
// Reference is the key that will retrieve the data from the endpoint.
Reference Reference
}
// An Endpoint identifies an instance of a service, encompassing an address
// such as a domain name and information (the Transport) about how to interpret
// that address.
type Endpoint struct {
// Transport specifies how the network address is to be interpreted,
// for instance that it is the URL of an HTTP service.
Transport Transport
// NetAddr returns the (typically) network address of the data.
NetAddr NetAddr
}
// A NetAddr is the network address of service. It is interpreted by Dialer's
// Dial method to connect to the service.
type NetAddr string
// A Reference is the string identifying an item in a StoreServer. It must
// be a valid UTF-8-encoded Unicode string and not contain U+FFFD.
type Reference string
// These special references are used to obtain out-of-band information from
// StoreServer implementations. StoreServers are not required to support them,
// in which case they may return errors.NotExist.
var (
// HealthMetadata is used to check that a StoreServer is up. Servers
// need not return any special response when asked for this reference.
HealthMetadata Reference = "metadata:Health"
// HTTPBaseMetadata is used to obtain a base URL from which references
// may be requested by HTTP(S). The server may return a URL to which
// a reference may be appended to obtain that reference's data.
HTTPBaseMetadata Reference = "metadata:HTTP-Base"
// FlushWritebacksMetadata is used as a signal to flush the cache.
// A Get will return only after all writebacks have completed.
FlushWritebacksMetadata Reference = "metadata:FlushWritebacks"
// ListRefsMetadata is used by administrators to enumerate the
// references held by a StoreServer. Callers pass this value verbatim
// for the initial request and append a pagination token for subsequent
// requests. The response from such a request is a JSON-encoded
// ListRefsResponse.
ListRefsMetadata Reference = "metadata:ListRefs:"
)
// ListRefsResponse describes a response from a StoreServer.Get
// call for ListRefsMetadata.
type ListRefsResponse struct {
// Refs holds the reference information.
Refs []ListRefsItem
// Next holds the token to fetch the next page,
// or the empty string if this is the last page.
Next string
}
// ListRefsItem describes a reference in a StoreServer,
// returned as part of a ListRefsResponse.
type ListRefsItem struct {
// Ref holds the reference name.
Ref Reference
// Size the length of the reference data.
Size int64
}
// Signature is an ECDSA signature.
type Signature struct {
R, S *big.Int
}
// DEHash is a hash of the Name, Link, Attribute, Packing, and Time
// fields of a DirEntry. When using EE or EEIntegrity the hash also includes the
// block checksums; when using EE it includes the block encryption key.
type DEHash []byte
// Factotum implements an agent, potentially remote, to handle private key operations.
type Factotum interface {
// DirEntryHash is a summary used in signing and verifying directory entries.
DirEntryHash(n, l PathName, a Attribute, p Packing, t Time, dkey, hash []byte) DEHash
// FileSign ECDSA-signs DirEntry fields and, in some packings, file contents.
FileSign(hash DEHash) (Signature, error)
// ScalarMult is the bare private key operator, used in unwrapping packed data.
// Each call needs security review to ensure it cannot be abused as a signing
// oracle. Read https://en.wikipedia.org/wiki/Confused_deputy_problem.
ScalarMult(keyHash []byte, c elliptic.Curve, x, y *big.Int) (sx, sy *big.Int, err error)
// Sign signs a slice of bytes with the factotum's private key.
// The argument hash should be a cryptographic hash of the message you want to sign,
// no longer than your key's curve order. Don't use without a security consult.
Sign(hash []byte) (Signature, error)
// Pop derives a Factotum that defaults to the previous key.
Pop() Factotum
// PublicKey returns the user's public key in canonical string format.
PublicKey() PublicKey
// PublicKeyFromHash returns the matching public key or an error.
PublicKeyFromHash(keyHash []byte) (PublicKey, error)
}
// A Packing identifies the technique for turning the data pointed to by
// a key into the user's data. This may involve checksum verification,
// decrypting, signature checking, or nothing at all.
// Secondary data such as encryption keys may be required to implement
// the packing. That data appears in the API as arguments and struct fields
// called packdata.
type Packing uint8
// BlockPacker operates on a DirEntry, packing and signing DirBlocks.
type BlockPacker interface {
// Pack takes cleartext data and returns the packed ciphertext,
// appending a DirBlock to the DirEntry.
//
// The ciphertext slice remains valid until the next call to Pack.
Pack(cleartext []byte) (ciphertext []byte, err error)
// SetLocation updates the Location field of the last-Packed DirBlock.
SetLocation(Location)
// Close updates the Signature for the DirEntry and releases any
// resources associated with the packing operation.
Close() error
}
// BlockUnpacker operates on a DirEntry, unpacking and verifying its DirBlocks.
type BlockUnpacker interface {
// NextBlock returns the next DirBlock in the sequence and true,
// or a zero DirBlock and false if there are no more blocks to unpack.
NextBlock() (DirBlock, bool)
// SeekBlock returns the nth DirBlock and true,
// or a zero DirBlock and false if the nth block does not exist.
SeekBlock(n int) (DirBlock, bool)
// Unpack takes ciphertext returns the cleartext. If appropriate, the
// result is verified as correct according to the block's Packdata.
//
// The cleartext slice remains valid until the next call to Unpack.
Unpack(ciphertext []byte) (cleartext []byte, err error)
// Close releases any resources associated with the unpacking
// operation.
Close() error
}
// Packer provides the implementation of a Packing. The pack package binds
// Packing values to the concrete implementations of this interface.
type Packer interface {
// Packing returns the integer identifier of this Packing algorithm.
Packing() Packing
// String returns the name of this packer.
String() string
// Pack returns a BlockPacker that packs blocks
// into the given DirEntry.
Pack(Config, *DirEntry) (BlockPacker, error)
// Unpack returns a BlockUnpacker that unpacks blocks
// from the given DirEntry.
Unpack(Config, *DirEntry) (BlockUnpacker, error)
// PackLen returns an upper bound on the number of bytes required
// to store the cleartext after packing.
// PackLen might update the entry's Packdata field.
// PackLen returns -1 if there is an error.
PackLen(config Config, cleartext []byte, entry *DirEntry) int
// UnpackLen returns an upper bound on the number of bytes
// required to store the unpacked cleartext.
// UnpackLen might update the entry's Packdata field.
// UnpackLen returns -1 if there is an error.
UnpackLen(config Config, ciphertext []byte, entry *DirEntry) int
// ReaderHashes returns SHA-256 hashes of the public keys able to decrypt the
// associated ciphertext.
ReaderHashes(packdata []byte) ([][]byte, error)
// Share updates each packdata element to enable all the readers,
// and only those readers, to be able to decrypt the associated ciphertext,
// which is held separate from this call. It is used to repair incorrect
// key wrapping after access rights are changed.
// In case of error, Share skips processing for that reader or packdata.
// If packdata[i] is nil on return, it was skipped.
// Share trusts the caller to check the arguments are not malicious.
// To enable all Upspin users to decrypt the ciphertext, include
// AllReadersKey among the provided reader keys.
//
// TODO: It would be nice if DirServer provided a method to report
// which items need updates, so this could be automated.
Share(config Config, readers []PublicKey, packdata []*[]byte)
// Name updates the DirEntry to refer to a new path. If the new
// path is in a different directory, the wrapped keys are reduced to
// only that of the Upspin user invoking the method. The Packdata
// in entry must contain a wrapped key for that user.
Name(config Config, entry *DirEntry, path PathName) error
// SetTime changes the Time field in a DirEntry and recomputes
// its signature.
SetTime(config Config, entry *DirEntry, time Time) error
// Countersign updates the signatures in the DirEntry when a writer
// is in the process of switching to a new key. It checks that
// the first existing signature verifies under the old key, copies
// that one over the second existing signature, and creates a new
// first signature using the key from factotum.
Countersign(oldKey PublicKey, f Factotum, d *DirEntry) error
// UnpackableByAll reports whether the packed data may be unpacked by
// all Upspin users. Access and Group files must have this property, as
// should any files for which access.AllUsers have the read permission.
UnpackableByAll(d *DirEntry) (bool, error)
}
const (
// UnassignedPack is not a packer, but a special value indicating no
// packer was chosen. It is an error to use this value in a DirEntry
// except when creating a directory, in which case the DirServer will
// assign the proper packing.
UnassignedPack Packing = 0
// PlainPack is a no-encryption, no-integrity packing. Bytes are copied
// untouched. DirEntry fields SignedName and so on are signed.
PlainPack Packing = 1
// Packings from 2 through 19 are not for production use. This region
// is reserved for debugging and other temporary packing implementations.
// Packings from 20 and above (as well as PlainPack) are fixed in
// value and semantics and may be used in production.
// EEPack provides elliptic-curve end-to-end confidentiality and
// integrity protection. It stores AES-encrypted data, with metadata
// including an ECDSA signature and ECDH-wrapped keys.
// (NIST SP 800-57 Pt.1 Rev.4 section 5.6.1)
// A signature and a per-file symmetric encryption key, wrapped
// for each reader, are encoded in Packdata.
// User keys specify a curve:
// "p256": AES-256, SHA-256, and curve P256; strength 128.
// "p384": AES-256, SHA-512, and curve P384; strength 192.
// "p521": AES-256, SHA-512, and curve P521; strength 256.
// TODO(ehg) add "25519": x/crypto/curve25519, github.com/agl/ed25519
EEPack Packing = 20
// EEIntegrityPack provides elliptic-curve end-to-end integrity protection,
// like EEPack, but provides no confidentiality.
// It is typically used when read access is "all".
EEIntegrityPack Packing = 22
)
// User represents all the public information about an Upspin user as returned by KeyServer.
type User struct {
// Name represents the user's name as an e-mail address, such as ann@example.com.
Name UserName
// Dirs is a slice of DirServer endpoints where the user's root directory may be located,
// which should be contacted in order when trying to access the user's tree. Multiple
// entries represent mirrors, which are as yet unimplemented. TODO.
Dirs []Endpoint
// Stores is a slice of StoreServer endpoints where the user's data is primarily written to,
// which should be contacted in order when trying to access the user's data. Multiple
// entries represent mirrors, which are as yet unimplemented. TODO.
Stores []Endpoint
// PublicKey is the user's current public key.
PublicKey PublicKey
}
// The KeyServer interface provides access to public information about users.
type KeyServer interface {
Dialer
Service
// Lookup returns all public information about a user.
Lookup(userName UserName) (*User, error)
// Put sets or updates information about a user. The user's name must
// match the authenticated user. The call can update any field except
// the user name.
// To add new users, see the signup subcommand of cmd/upspin.
Put(user *User) error
}
// A PublicKey can be seen by anyone and is used for authenticating a user.
type PublicKey string
// AllUsersKey is a sentinel PublicKey value used to indicate that a
// Packer.Share operation should make the data readable to anyone.
var AllUsersKey = PublicKey("read: all")
var (
// ErrFollowLink indicates that all or part of a path name has
// evaluated to a DirEntry that is a link. In that case, the returned
// DirEntry will be that of the link, and its Name field is guaranteed
// to be an element-wise prefix of the argument path name. The caller
// should retry the operation, substituting that prefix (which may be
// the entire name) with the contents of the Link field of the returned
// DirEntry.
ErrFollowLink = errors.New("action incomplete: must follow link")
// ErrNotSupported indicates that the server does not support the
// requested operation.
ErrNotSupported = errors.New("not supported")
)
// MaxLinkHops is the maximum number of links that will be followed
// when evaluating a single path name.
const MaxLinkHops = 20
// Special Sequence values for Watch that can be used in place of the
// Sequence argument in the Watch function.
const (
// WatchStart returns all known events.
WatchStart = -iota
// WatchCurrent first sends a sequence of events describing the entire
// tree rooted at name. The Events are sent in sequence such that a
// directory is sent before its contents. After the full tree has been
// sent, the operation proceeds as normal.
WatchCurrent
// WatchNew returns only new events.
WatchNew
)
// DirServer manages the name space for one or more users.
type DirServer interface {
Dialer
Service
// Lookup returns the directory entry for the named file.
//
// If the returned error is ErrFollowLink, the caller should
// retry the operation as outlined in the description for
// ErrFollowLink. Otherwise in the case of error the
// returned DirEntry will be nil.
Lookup(name PathName) (*DirEntry, error)
// Put stores the DirEntry in the directory server. The entry
// may be a plain file, a link, or a directory. (Only one of
// these attributes may be set.)
// In practice the data for the file should be stored in
// a StoreServer as specified by the blocks in the entry,
// all of which should be stored with the same packing.
//
// Within the DirEntry, several fields have special properties.
// Time represents a timestamp for the item. It is advisory only
// but is included in the packing signature and so should usually
// be set to a non-zero value.
//
// Sequence represents a sequence number that is incremented
// after each Put. If it is neither 0 nor -1, the DirServer will
// reject the Put operation if the file does not exist or, for an
// existing item, if the Sequence is not the same as that
// stored in the metadata. If it is -1, Put will fail if there
// is already an item with that name.
//
// The Name field of the DirEntry identifies where in the directory
// tree the entry belongs. The SignedName field, which usually has the
// same value, is the name used to sign the DirEntry to guarantee its
// security. They may differ if an entry appears in multiple locations,
// such as in its original location plus within a second tree holding
// a snapshot of the original tree but starting from a different root.
//
// Most software will concern itself only with the Name field unless
// generating or validating the entry's signature.
//
// All but the last element of the path name must already exist
// and be directories or links. The final element, if it exists,
// must not be a directory. If something is already stored under
// the path, the new location and packdata replace the old.
//
// If the returned error is ErrFollowLink, the caller should
// retry the operation as outlined in the description for
// ErrFollowLink (with the added step of updating the
// Name field of the argument DirEntry). For any other error,
// the return DirEntry will be nil.
//
// A successful Put returns an incomplete DirEntry (see the
// description of AttrIncomplete) containing only the
// new sequence number.
Put(entry *DirEntry) (*DirEntry, error)
// Glob matches the pattern against the file names of the full
// rooted tree. That is, the pattern must look like a full path
// name, but elements of the path may contain metacharacters.
// Matching is done using Go's path.Match elementwise. The user
// name must be present in the pattern and is treated as a literal
// even if it contains metacharacters.
// If the caller has no read permission for the items named in the
// DirEntries, the returned Location and Packdata fields are cleared.
//
// If the returned error is ErrFollowLink, one or more of the
// returned DirEntries is a link (the others are completely
// evaluated). The caller should retry the operation for those
// DirEntries as outlined in the description for ErrFollowLink,
// updating the pattern as appropriate. Note that any returned
// links may only partially match the original argument pattern.
//
// If the pattern evaluates to one or more name that identifies
// a link, the DirEntry for the link is returned, not the target.
// This is analogous to passing false as the second argument
// to Client.Lookup.
Glob(pattern string) ([]*DirEntry, error)
// Delete deletes the DirEntry for a name from the directory service.
// It does not delete the data it references; use StoreServer.Delete
// for that. If the name identifies a link, Delete will delete the
// link itself, not its target.
//
// If the returned error is ErrFollowLink, the caller should
// retry the operation as outlined in the description for
// ErrFollowLink. (And in that case, the DirEntry will never
// represent the full path name of the argument.) Otherwise, the
// returned DirEntry will be nil whether the operation succeeded
// or not.
Delete(name PathName) (*DirEntry, error)
// WhichAccess returns the DirEntry of the Access file that is
// responsible for the access rights defined for the named item.
// WhichAccess requires that the calling user have at least one access
// right granted for the argument name. If not, WhichAccess will return
// a "does not exist" error, even if the item and/or the Access file
// exist.
//
// If the returned error is ErrFollowLink, the caller should
// retry the operation as outlined in the description for
// ErrFollowLink. Otherwise, in the case of error the returned
// DirEntry will be nil.
WhichAccess(name PathName) (*DirEntry, error)
// Watch returns a channel of Events that describe operations that
// affect the specified path and any of its descendants, beginning
// at the specified sequence number for the corresponding user root.
//
// If sequence is 0, all events known to the DirServer are sent.
//
// If sequence is WatchCurrent, the server first sends a sequence
// of events describing the entire tree rooted at name. The Events are
// sent in sequence such that a directory is sent before its contents.
// After the full tree has been sent, the operation proceeds as normal.
//
// If sequence is WatchNew, the server sends only new events.
//
// If the sequence is otherwise invalid, this is reported by the
// server sending a single event with a non-nil Error field with
// Kind=errors.Invalid. The events channel is then closed.
//
// When the provided done channel is closed the event channel
// is closed by the server.
//
// To receive an event for a given path under name, the caller must have
// one or more of the Upspin access rights to that path. Events for
// which the caller does not have enough rights to watch will not be
// sent. If the caller has rights but not Read, the entry will be
// present but incomplete (see the description of AttrIncomplete). If
// the name does not exist, Watch will succeed and report events if and
// when it is created.
//
// If the caller does not consume events in a timely fashion
// the server will close the event channel.
//
// If this server does not support this method it returns
// ErrNotSupported.
//
// The only errors returned by the Watch method itself are
// to report that the name is invalid or refers to a non-existent
// root, or that the operation is not supported.
Watch(name PathName, sequence int64, done <-chan struct{}) (<-chan Event, error)
}
// Event represents the creation, modification, or deletion of a DirEntry
// within a DirServer.
type Event struct {
// Entry is the DirEntry to which the event pertains. Its Sequence
// field captures the ordering of events for this user.
Entry *DirEntry
// Delete is true only if the entry is being deleted;
// otherwise it is being created or modified.
Delete bool
// Error is non-nil if an error occurred while waiting for events.
// In that case, all other fields are zero.
Error error
}
// Time represents a timestamp in units of seconds since
// the Unix epoch, Jan 1 1970 0:00 UTC.
type Time int64
// DirEntry represents the directory information for a file.
// The blocks of a file represent contiguous data. There are no
// holes and no overlaps and the first block always has offset 0.
// Name and SignedName must not be empty. See comments in DirServer.Put.
type DirEntry struct {
// Fields contributing to the signature.
SignedName PathName // The full path name of the file used for signing.
Link PathName // The link target, iff the DirEntry has Attr=AttrLink.
Attr Attribute // Attributes for the DirEntry.
Packing Packing // Packing used for every block in file.
Time Time // Time associated with file; might be when it was last written.
Blocks []DirBlock // Descriptors for each block. A nil or empty slice represents an empty file.
Packdata []byte // Information maintained by the packing algorithm.
// Field determining the key used for the signature, hence also tamper-resistant.
Writer UserName // Writer of the file, often the same as owner.
// Fields not included in the signature.
Name PathName // The full path name of the file. Only the last element can be a link.
Sequence int64 // The sequence (version) number of the item.
}
// BlockSize is an arbitrarily chosen size that packers use when breaking
// data into blocks for storage. Clients are free to use any size, but this
// value is used in various helper libraries.
// This is also the default value for flags.BlockSize, but must be kept in
// sync manually because the flags package cannot import this package.
const BlockSize = 1024 * 1024
// MaxBlockSize is the maximum size permitted for a block. The limit
// guarantees that 32-bit machines can process the data without problems.
const MaxBlockSize = 1024 * 1024 * 1024
// DirBlock describes a block of data representing a contiguous section of a file.
// The block may be of any non-negative size, but in large files is usually
// BlockSize long.
type DirBlock struct {
Location Location // Location of data in store.
Offset int64 // Byte offset of start of block's data in file.
Size int64 // Length of block data in bytes.
Packdata []byte // Information maintained by the packing algorithm.
}
// Attribute defines the attributes for a DirEntry.
type Attribute byte
// Supported Attributes.
const (
// AttrNone is the default attribute, identifying a plain data object.
AttrNone = Attribute(0)
// AttrDirectory identifies a directory. It must be the only attribute.
AttrDirectory = Attribute(1 << 0)
// AttrLink identifies a link. It must be the only attribute.
// A link is a path name whose DirEntry identifies another
// "target" item in the tree, similar to a Unix symbolic link.
// The target of a link may be another link.
// The target path is stored in the Link field of the DirEntry.
// A link DirEntry holds zero DirBlocks.
AttrLink = Attribute(1 << 1)
// AttrIncomplete identifies a DirEntry whose Blocks and Packdata
// fields are elided for access control purposes, or the reply to
// a successful Put containing only the updated sequence number.
AttrIncomplete = Attribute(1 << 2)
)
// Sequence numbers.
// Sequence numbers are controlled by the DirServer. For a given user root they
// start at SeqBase and grow monotonically (typically but not necessarily by
// one) with each Put or Delete operation in that user's tree. After an item is
// Put to or Deleted from the DirServer, the Sequence of that item (or its
// directory, for a Delete) and all of the directories on its path will be set
// to the next Sequence number for the user tree. Thus, as a corollary, any
// directory but in particular the user root always has the Sequence number of
// the most recently modified item at that level or deeper in the tree.
//
// When a file or directory is being created, the sequence number in the
// DirEntry provided to Put must be either SeqNotExist or SeqIgnore.
const (
SeqNotExist = -1 // Put will fail if item exists.
SeqIgnore = 0 // Put will not check sequence number, but will update it.
SeqBase = 1 // Base at which valid sequence numbers start.
)
// Refdata attaches information about cacheability to a Reference. A Refdata is
// returned by a StoreServer to describe the lifetime of the data associated with
// a Reference.
type Refdata struct {
Reference Reference // The reference itself.
Volatile bool // If true, the data might change on every Get and cannot be cached.
Duration time.Duration // For non-volatile data, the predicted cacheable lifetime; 0 means forever.
}
// The StoreServer saves and retrieves data without interpretation.
type StoreServer interface {
Dialer
Service
// Get attempts to retrieve the data identified by the reference.
// Three things might happen:
// 1. The data is in this StoreServer. It is returned. The Location slice
// and error are nil. Refdata contains information about the data.
// 2. The data is not in this StoreServer, but may be in one or more
// other locations known to the store. The slice of Locations
// is returned. The data, Refdata, Locations, and error are nil.
// 3. An error occurs. The data, Locations and Refdata are nil
// and the error describes the problem.
Get(ref Reference) ([]byte, *Refdata, []Location, error)
// Put puts the data into the store and returns the reference
// to be used to retrieve it.
Put(data []byte) (*Refdata, error)
// Delete permanently removes all storage space associated
// with the reference. After a successful Delete, calls to Get with the
// same reference will fail. If the reference is not found, an error is
// returned. Implementations may disable this method except for
// privileged users.
Delete(ref Reference) error
}
// Client API.
// The Client interface provides a higher-level API suitable for applications
// that wish to access Upspin's name space. Most Upspin programs should
// use the Client interface to talk to Upspin services.
//
// When Client evaluates a path name and encounters a link, it evaluates the
// link, iteratively if necessary, until it reaches an item that is not a link.
// (The DirServer interface does not evaluate links.)
//
// In methods where a name is evaluated and a DirEntry returned,
// if links were evaluated in processing the operation, the Name field
// of the DirEntry will be different from the argument path name and
// will hold the link-free path to item.
type Client interface {
// Get returns the clear, decrypted data stored under the given name.
// It is intended only for special purposes, since it will allocate memory
// for the entire "blob" to return. The file-like API below can be less
// memory-intensive.
Get(name PathName) ([]byte, error)
// Lookup returns the directory entry for the named file. The
// boolean determines whether, if the final path element is a link,
// to return the DirEntry for the link (false) or for the target of
// the link (true).
Lookup(name PathName, followFinal bool) (*DirEntry, error)
// Put stores the data at the given name. If something is already
// stored with that name, it will no longer be available using the
// name, although it may still exist in the storage server. (See
// the documentation for Delete.) Like Get, it is not the usual
// access method. The file-like API is preferred.
//
// A successful Put returns an incomplete DirEntry (see the
// description of AttrIncomplete) containing only the
// new sequence number.
Put(name PathName, data []byte) (*DirEntry, error)
// PutLink creates a link from the new name to the old name. The
// new name must not look like the path to an Access or Group file.
// If something is already stored with the new name, it is first
// deleted from the directory but its storage is not deleted from
// the Store. (See the documentation for Delete.) The old name is
// not evaluated, that is, the resulting link will hold the
// argument to PutLink even if it refers to a path that itself
// contains links. The name is canonicalized, however (see
// path.Clean).
//
// A successful PutLink returns an incomplete DirEntry (see the
// description of AttrIncomplete) containing only the
// new sequence number.
PutLink(oldName, newName PathName) (*DirEntry, error)
// PutDuplicate creates a new name for the references referred to
// by the old name. Subsequent Puts to either name do not effect
// the contents referred to by the other. There must be no existing
// item with the new name. If the final element of the path name
// is a link, PutDuplicate will duplicate the link and not the
// link target.
//
// A successful PutDuplicate returns an incomplete DirEntry (see the
// description of AttrIncomplete) containing only the
// new sequence number.
PutDuplicate(oldName, newName PathName) (*DirEntry, error)
// MakeDirectory creates a directory with the given name, which
// must not already exist. All but the last element of the path
// name must already exist and be directories.
//
// A successful MakeDirectory returns an incomplete DirEntry (see the
// description of AttrIncomplete) containing only the
// new sequence number.
MakeDirectory(dirName PathName) (*DirEntry, error)
// Rename renames oldName to newName. The old name is no longer valid.
// If the final element of the path name is a link, Rename will
// Rename the link itself, not the link target.
Rename(oldName, newName PathName) error
// SetTime sets the time in name's DirEntry. If the final element
// of the path name is a link, SetTime will affect the link itself,
// not the link target.
SetTime(name PathName, t Time) error
// Delete deletes the DirEntry associated with the name. The
// storage referenced by the DirEntry is not deleted,
// although the storage server may garbage collect unreferenced
// data independently. If the final element of the path name is a
// link, Delete will delete the link itself, not the link target.
Delete(name PathName) error
// Glob matches the pattern against the file names of the full
// rooted tree. That is, the pattern must look like a full path
// name, but elements of the path may contain metacharacters.
// Matching is done using Go's path.Match elementwise. The user
// name must be present in the pattern and is treated as a literal
// even if it contains metacharacters. Note that if links are
// evaluated while executing Glob, the Name fields of the returned
// DirEntries might not match the original argument pattern.
Glob(pattern string) ([]*DirEntry, error)
// Open and Create are file-like methods similar to Go's os.File API.
// The name, however, is a fully-qualified upspin PathName.
Create(name PathName) (File, error)
Open(name PathName) (File, error)
// DirServer returns an error or a reachable bound DirServer for the user.
DirServer(name PathName) (DirServer, error)
}
// The File interface has semantics and an API that parallels a subset
// of Go's os.File. The main semantic difference, besides the limited
// method set, is that a Read will only return once the entire contents
// have been decrypted and verified.
type File interface {
// Close releases the resources. For a writable file, it also
// writes the accumulated data in a StoreServer. After a
// Close, successful or not, all methods of File except Name
// will fail.
Close() error
// Name returns the full path name of the File.
Name() PathName
// Read, ReadAt, Write, WriteAt and Seek implement
// the standard Go interfaces io.Reader, etc.
// Because of the nature of Upspin storage, the entire
// item might need to be read into memory by the
// implementation before Read can return any data.
// Similarly, Write might accumulate all data and only
// flush to storage once Close is called.
Read(b []byte) (n int, err error)
ReadAt(b []byte, off int64) (n int, err error)
Write(b []byte) (n int, err error)
WriteAt(b []byte, off int64) (n int, err error)
Seek(offset int64, whence int) (ret int64, err error)
}
// Config contains client information such as the user's keys and
// preferred KeyServer, DirServer, and StoreServer endpoints.
type Config interface {
// The name of the user requesting access.
UserName() UserName
// Factotum holds the user's cryptographic keys and encapsulates crypto operations.
Factotum() Factotum
// Packing is the Packing to use when creating new data items, although
// it may be overridden by the implementation, such as to use a cleartext
// packing for a globally readable ("read:all") file.
Packing() Packing
// KeyEndpoint is the endpoint of the KeyServer to contact to retrieve keys.
KeyEndpoint() Endpoint
// DirEndpoint is the endpoint of the DirServer in which to place new data items. It is
// usually the location of the user's root.
DirEndpoint() Endpoint
// StoreEndpoint is the endpoint of the StoreServer in which to place new data items.
StoreEndpoint() Endpoint
// Value returns the value for the given configuration key.
Value(key string) string
}
// Dialer defines how to connect and authenticate to a server. Each
// service type (KeyServer, DirServer, StoreServer) implements the methods of
// the Dialer interface. These methods are not used directly by
// clients. Instead, clients should use the methods of
// the Upspin "bind" package to connect to services.
type Dialer interface {
// Dial connects to the service and performs any needed authentication.
Dial(Config, Endpoint) (Service, error)
}
// Service is the general interface returned by a dialer. It includes
// methods to configure the service and report its setup.
type Service interface {
// Endpoint returns the network endpoint of the server.
Endpoint() Endpoint
// Close closes the connection to the service and releases all resources used.
// A Service may not be re-used after close.
Close()
}