Elfin Directory

Arrange Permissioned Contents on Decentralized Storages

Note

Currently this document only specifies immutable directory on IPFS. Specifications for other decentralized storages will come soon.

IPFS supports Immutable Filesystem, and a IPFS URL can actually point to a directory.

Sometimes we want to share several files as a whole through. For example:

  1. HLS playlist (.m3u8) file and the segment files
  2. A html file and its resources (images, videos, css, js)
  3. A markdown (.md) file and its images
  4. A video file and several subtitle files for it

As a convention, in the IPFS immutable directory:

  1. The entry file must be named as “index”, such as index.m3u8, index.html, index.md
  2. There can be a “readme.md” file to briefly introduce the files in this directory. It can have only text contents or include base64-encoded images.
  3. There must be a “config.json” file to guide viewers in decrypting some of the files in this directory. It is allowed that some of the files are not encrypted.

Metadata’s schema

The schema of the “config.json” file is as follows:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "ElfinGuard Recryptor Configuration",
    "description": "Configures the ElfinGuard Recryptor to Decrypt Files",
    "type": "object",
    "properties": {
        "version": {
            "description": "The Version of ElfinGuard Protocol",
            "type": "integer"
            "minimum": 0,
            "exclusiveMinimum": false
        },
        "introduction": {
            "type": "string"
            "description": "briefly introduce the contents in this directory",
        },
        "keywords": {
            "type": "string"
            "description": "some keywords which help search engines indexing this elfin directory, seperated by commas",
        },
        "author": {
            "name": {
                "type": "string"
                "description": "The author's name",
            },
            "homepage": {
                "type": "string"
                "description": "The home page of the author (https or ipns)",
            },
            "evm_address": {
                "type": "string"
                "description": "The author's EVM address",
            }
        },
        "files": {
            "type": "array",
            "description": "provide information for decrypting some of the files in the directory",
            "items": {
                 "type": "object",
                 "properties": {
                     "filename": {
                         "type": "string"
                         "description": "the name of a file in this directory",
                     },
                     "fileid": {
                         "type": "string"
                         "description": "a unique id for this file",
                     },
                     "size": {
                         "type": "integer"
                         "description": "the size of the original file before encryption",
                     },
                     "recryptorsalt": {
                         "type": "string"
                         "description": "random bytes generated by the recryptor",
                     },
                     "decryptionguides": {
                         "description": "Each blockchain has a dedicated decryption guide",
                         "type": "array",
                         "items": {
                              "type": "object",
                              "properties": {
                                  "chainid": {
                                      "type": "string",
                                      "description": "a hex string indicating the target chain's ID"
                                  },
                                  "contract": {
                                      "type": "string",
                                      "description": "the EVM address of the authorization contract"
                                  },
                                  "function": {
                                      "type": "string",
                                      "description": "the signature of the function to be called"
                                  },
                                  "threshold": {
                                      "type": "integer"
                                      "description": "the minimum number of authorizers required to decrypt this file",
                                      "minimum": 1,
                                      "exclusiveMinimum": false
                                  },
                                  "authorizerlist": {
                                      "type": "array",
                                      "items": {
                                          "type": "string",
                                          "description": "the domain name of an authorizer"
                                      },
                                      "minItems": 1,
                                      "uniqueItems": true
                                  },
                                  "outdata": {
                                      "type": "string"
                                      "description": "the expected outdata from eth_call",
                                  },
                                  "encryptedparts": {
                                      "type": "array",
                                      "items": {
                                          "type": "string",
                                          "description": "base64-encoded shamir part encrypted with the grantcode from the authorizer"
                                      },
                                      "minItems": 1,
                                      "uniqueItems": true
                                  }
                              }
                         }
                     }
                 }
            }
        }
    }
}

FormData for upload

To store a Elfin directory to IPFS, you must first submit the files that need encryption to the server side using the encryptChunk endpoint of the recryptor. After they are ready, you can upload the files in Elfin directory using FormData (multipart/form-data). A FormData object should be created using the append method, with the following arguments:

  1. name: the full name of the file. A Elfin directory can contain subdirectories. So the full name may contain “/”.
  2. value: For a non-encrypted file, this is its Blob content. For an encrypted file, this is a hex string representing its recryptorsalt.