SAFE Network

Low-Level API

October 13, 2016

Low-Level API

  • Structured Data API
  • Appendable Data API
  • Immutable Data API
  • Data Identifier API

Permission

Apps must request the LOW_LEVEL_API access permission to invoke the low-level API to store or read encrypted data.

Unauthorized access is granted by default for reading public data using the low-level API.

Structured Data

pub struct StructuredData {
    type_tag: u64,
    name: XorName,
    data: Vec<u8>,
    previous_owner_keys: Vec<PublicKey>,
    version: u64,
    current_owner_keys: Vec<PublicKey>,
    previous_owner_signatures: Vec<Signature>,
}

Structured data has a size restriction of 100 KiB including its internals. If the size is more than permitted size, an error is returned after serialization.

Structured Data

Type Tag Description
Unversioned 500 Has only the one latest copy
Versioned 501 ​Will hold version history. Can fetch an older version based on a version number
Custom 15000 > Apps are free to use any type tag value greater than 15000

If the size of the data being passed is greater than 100 KiB, the versioned and unversioned structured data will ensure that the data is managed and stored successfully. But for custom type tags it becomes the responsibility of the app to handle the size restriction.

XorName

/// Constant byte length of `XorName`.
pub const XOR_NAME_LEN: usize = 32;

/// Constant bit length of `XorName`.
pub const XOR_NAME_BITS: usize = XOR_NAME_LEN * 8;


pub struct XorName(pub [u8; XOR_NAME_LEN]);

The ID of a Structured Data is a base64 string representing a [u8; 32] array.

The type tag and ID combination is needed for fetching a Structured Data from the network.

Cipher Opts

Encryption Description
PLAIN Data is not encrypted
SYMMETRIC This type of encryption is used when encrypting data for yourself. No one else will be able to read it.
ASYMMETRIC This type of encryption is used when encrypting data for someone else to read. After encrypting, even the sender wouldn’t be able to read the data anymore.

Handles

A StructuredData handle is needed for working with a structured data and it must be dropped after usage.

DELETE /structured-data/handle/:handleId

Create Structured Data

{
  name: [u8; 32] of base64 string,
  typeTag: Number,
  // optional, defaults to 501
  cipherOpts: u64 representing cipher-opts handle
  // optional, defaults to PLAIN
}
{
  handleId: u64 representing the StructuredData handle Id
}

Response

Request

POST /structured-data
export const createStructuredData = (token, name, data, cipherHandle) => ({
  type: ACTION_TYPES.CREATE_STRUCTURED_DATA,
  payload: {
    request: {
      method: 'post',
      url: '/structured-data',
      headers: {
        'Authorization': token
      },
      data: {
        name,
        typeTag: CONSTANTS.TAG_TYPE.DEFAULT,
        cipherOpts: cipherHandle,
        data: new Buffer(JSON.stringify(data)).toString('base64')
      }
    }
  }
});
export const generateStructredDataId = () => {
  return base64.encode(crypto.randomBytes(32).toString('base64'));
};

Examples of endpoints

// Create structured data
POST /structured-data
// Save structured data - POST
POST /structured-data/:handleId
// Get metadata of structured data
GET /structured-data/metadata/:handleId
// Get structured data handle
GET /structured-data/handle/:dataIdHandle
// Read structured data
GET /structured-data/:handleId/:version?
// Save structured data - PUT
PUT /structured-data/:handleId
// Update data of structured data
PATCH /structured-data/:handleId
// Get serialise structured data 
GET /structured-data/serialise/:handleId
// Drop structured data handle
DELETE /structured-data/handle/:handleId
// Delete structured data
DELETE /structured-data/:handleId

Appendable Data

  • PrivAppendableData
  • PubAppendableData

Private appendable data

pub struct PrivAppendableData {
    /// The name of this data chunk.
    pub name: XorName,
    /// The version, i.e. the number of times this has been updated by a `Post` request.
    pub version: u64,
    /// The keys of the current owners that have the right to modify this data.
    pub current_owner_keys: Vec<PublicKey>,
    /// The keys of the owners of the chunk's previous version.
    pub previous_owner_keys: Vec<PublicKey>,
    /// The filter defining who is allowed to append items.
    pub filter: Filter,
    /// The key to use for encrypting appended data items.
    pub encrypt_key: box_::PublicKey,
    /// A collection of previously deleted data items.
    pub deleted_data: BTreeSet<PrivAppendedData>,
    /// The signatures of the above fields by the previous owners, confirming the last update.
    pub previous_owner_signatures: Vec<Signature>, // All the above fields
    /// The collection of appended data items.
    /// These are not signed by the owners,
    /// as they change even between `Post`s.
    pub data: BTreeSet<PrivAppendedData>, // Unsigned
}

Public appendable data

pub struct PubAppendableData {
    /// The name of this data chunk.
    pub name: XorName,
    /// The version, i.e. the number of times this has been updated by a `Post` request.
    pub version: u64,
    /// The keys of the current owners that have the right to modify this data.
    pub current_owner_keys: Vec<PublicKey>,
    /// The keys of the owners of the chunk's previous version.
    pub previous_owner_keys: Vec<PublicKey>,
    /// The filter defining who is allowed to append items.
    pub filter: Filter,
    /// A collection of previously deleted data items.
    pub deleted_data: BTreeSet<AppendedData>,
    /// The signatures of the above fields by the previous owners, confirming the last update.
    pub previous_owner_signatures: Vec<Signature>,
    /// The collection of appended data items.
    /// These are not signed by the owners, as they change
    /// even between `Post`s.
    pub data: BTreeSet<AppendedData>,
}

Immutable Data

pub struct ImmutableData {
    name: XorName,
    value: Vec<u8>,
}

Data Identifier

/// An identifier to address a data chunk.
pub enum DataIdentifier {
    /// Data request, (Identifier, TypeTag) pair
    /// for name resolution, for StructuredData.
    Structured(XorName, u64),
    /// Data request, (Identifier), for `ImmutableData`.
    Immutable(XorName),
    /// Request for PlainData.
    Plain(XorName),
    /// Request for public appendable data.
    PubAppendable(XorName),
    /// Request for private appendable data.
    PrivAppendable(XorName),
}