Inbox Entries
Inboxes allow users to receive encrypted entries, either from external or internal sources.
-
Internal sources are people who have access to an Inbox, or are simply registered in a given Context. Those users are known to your application, and their entries can be linked to their accounts.
-
External sources are people from the outside; they do not have an account linked with your app. For example, someone who fills out an online contact form without the need to create an account.
The key difference between Inboxes and other PrivMX tools is that people don't need accounts in your app to be able to submit entries.
About Entries
The structure of an entry and a brief description of its elements is outlined in the following table:
Field | Type | Encrypted | Description |
---|---|---|---|
data | binary | Content of the entry | |
files | File[] | List of attached files | |
authorPubKey | string | Public key of the author |
Define Data Structure
Inbox's architecture does not require you to use a specific data structure inside the entries. Before working with Inboxes, define the structure of your entries.
Info
We recommend future-proofing your entries by choosing an easily modifiable format. It is a good idea to include both a type
and a version
field in the structure.
Example: Form with Text Answer
{
“content”: {
"answer": USER_PROVIDED_TEXT
},
“version”:number,
“type”: "text_answer",
}
The type
field allows future support for different types of entries like: "select_answer"
, or "multi_select"
.
And in case of changing the schema, you can always distinguish between them using "version"
field.
Remember that this is only an example and you should consider your app's requirements and limitations.
Submitting Entries
To submit an entry, you need:
- URL of your PrivMX Bridge Instance
- Solution ID with at least one Inbox created
- ID of the Inbox to submit the entry
If you need more information about how to create an Inbox, go to Creating Inbox.
Sending Process
Sending entries is carried out in two (or three if files are attached) steps.
-
Preparing Entry
Use the
prepareEntry
method to provide the Inbox ID and the data you want to submit. Optionally, you can provide file handles and a private key.If you don't want to send any files, pass an empty array for the file handles.
const entryData = {
content: {
"answer": USER_PROVIDED_TEXT
},
version:number,
type: "text_answer",
}
const entryHandle = await inboxApi.prepareEntry(
inboxID,
this.strToUint8(JSON.stringify(entryData)),
[]
);For JavaScript reference go here.
-
Sending Entry
After preparing an entry you will receive an Inbox handle. In this case, all you have to do is pass it to
sendEntry
method.// previous code
await inboxApi.sendEntry(entryHandle)For JavaScript reference go here.
Working With Files
Inbox entries can include any number of files (in accordance with the predefined Inbox file configuration).
Each file may include its own public and private metadata to store additional information.
For example, to include file name and mimetype information, pass this data as JSON to the publicMeta
(or privateMeta
, if the file name contains sensitive information):
For example:
{
"name":FILE_NAME,
"mimetype": FILE_MIMETYPE
}
Attaching Files
Sending entries with attached files follows a similar process to sending entries without files. The main difference is that you must create file handles for each file and stream their content.
-
Preparing Entry
For each file you want to send, create a file handle. You can provide additional data, e.g. file name or its metadata.
If you’re creating a questionnaire, you can relate files with questions by putting question info in the file's metadata.
const selectedFile = //File selected by user
const filePrivateMeta = {
name: selectedFile.name,
mimetype: selectedFile.type
}
const fileHandle = inboxApi.createFileHandle(
strToUin8(""),
strToUin8(JSON.stringify(filePrivateMeta)),
selectedFile.size
)
// preparing entry as shown before
const entryHandle = await inboxApi.prepareEntry(
inboxID,
this.strToUint8(JSON.stringify(entryData)),
[fileHandle]
);For JavaScript reference go here.
-
Sending File Contents
For large files, it is recommended to stream the file content in small buffers rather than loading the entire file into memory. PrivMX Endpoint divides those buffers if required, then streams them to your PrivMX Bridge.
//previous code
const reader = await selectedFile.stream().getReader()
while(true){
const { done, value } = await reader.read();
if(done){
break;
}
await inboxApi.writeToFile(entryHandle, fileHandle, value)
} -
Sending Entry
Finally, send the entry in the same way as described before:
//previous code
await inboxApi.sendEntry(entryHandle)
Fetching Entries
Info
Fetching entries requires decoding them back into their original format. Depending on your data structure, you will need to parse and decode the fetched entries.
The process for fetching entries heavily depends on your entry format. Refer back to Define Data Structure if you need guidance on how to structure your entry.
Basic Entries
After fetching entries, you must first decrypt them back to their original format. For schema used earlier, this process looks like this:
//define how much you want to fetch and skip
const defaultQuery = {skip:0, limit:100, sortOrder: "asc"}
const readList = inboxApi.listEntries(inboxId, defaultQuery)
const decodedEntries = readList.readItems(entry => {
return {
...entry,
data: JSON.parse(uint8ToStr(entry.data))
}
})
Entries with Files
Entries include only file metadata, without their contents. Similar to entries data, you have to decode them before using.
For example, if you saved name and metadata of a file in its privateMeta
,
you can read them like this:
//define how much you want to fetch and skip
const defaultQuery = {skip:0, limit:100, sortOrder: "asc"}
const readList = inboxApi.listEntries(inboxId, defaultQuery)
const decodedEntries = readList.readItems(entry => {
//decoding file meta first
const decodedFiles = entry.files.map(file => {
return {
...file,
privateMeta:JSON.parse(uint8ToStr(file.privateMeta)),
}
})
return {
...entry,
data: JSON.parse(uint8ToStr(entry.data)),
files:decodedFiles
}
})