This the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

The @platform documentation

All the documentation you need for building apps on the @platform

As the heart of the @platform, we developed the @protocol in Dart, a powerful language that can be used to develop mobile apps with Flutter, Google’s increasingly popular UI software framework. If you are new to Flutter or Dart, no problem! Many of our first developers knew nothing about these languages coming in. For guidance on Flutter installation and development, please visit flutter.dev. Regardless of your coding knowledge, we recommend that you begin with “Get Started.”

Welcome to the @platform:

Our Co-Founder and CTO, Colin Constable, has a message for you!

Where should I go next?

1 - The @sign foundation overview

Meet the atsign-foundation organization

The atsign-foundation

This organization is the home for a number of open source projects and repositories. They generally fall into three basic categories:

  1. An open specification for The @protocol.
  2. An open source platform(i.e @platform) implementation of the protocol.
  3. Documentation, samples and examples of how to use and implement the @platform.

The @protocol

The @protocol is a new internet protocol which is defined by an open specification document which is maintained in our Github repo.

Protocol Definition

To learn more about the @protocol, check out the full spec document

The @platform

The @platform is designed to help developers create end-to-end encrypted mobile applications. A full stack platform written in Dart and Flutter, it includes a wide range of libraries, services and widgets specifically designed for creating privacy-first applications on any platform.

Platform Definition

1.1 - Specification

The @protocol specification repository contains the specification document as well as other supporting documentation.

The @protocol Specification


Subject@protocol specification
Author(s)Colin Constable, Kevin Nickels, Jagannadh Vanghuri
Revisionv0.1.0 (draft)
DateJuly 5, 2021

Root Server

A Root Server should provide a lookup of where a Secondary Server for an @sign is running. This is similar to a DNS server.

When asking a Root Server for the lookup of a particular @sign the Root Server should respond with a null if the name does not exist and if the name exists the DNS name or address of the @server and the IP port number for that @sign should be returned.

Response:

<host>:<port>

The Root Server only has one verb - @exit and all other inputs are considered to be lookup requests.

Secondary Server

A Secondary Server is where an @sign user’s personal data should be stored. One interacts with a secondary using the verbs exposed by the protocol.

A Secondary Server should have 4 major sub components:

  1. Key Store
  2. Commit Log
  3. Access Log
  4. Notification Log

Verbs described in the document should be used to create, update, delete and retrieve information from the above sub components.

1. Key Store

Key store is a place where user data in a Secondary Server should be saved as key and value pairs. Apart from the value, an @sign user should be able to add certain metadata for a key.

Key

A key in the @protocol can be formed by using any alphanumeric and special characters (UTF-8) excluding “@”, “:” and a white space (" “). A key in a secondary can be any of the following 5 types:

  1. Public Key

    • A public key is a key which can be looked up by any @sign user.

    • A public key should be part of the scan verb result.

    • Format of the public key should be public::<@sign>.

    Example:

    public:location@alice

    The owner of the secondary should be allowed to update or delete the value of a public key.

  2. Private Key

    • A private key is a key which cannot be looked up any @sign user other than the one created it.

    • A private key should not be returned in a scan verb result.

    • Format of the private key should be privatekey::<@sign>.

    Example:

    privatekey:pk1@alice

    The owner of the secondary should be allowed to update or delete the value of a private key.

  3. User key

    • A user key can only be looked up by an @sign user with whom the data has been shared.
    • A user key should be part of the scan verb result only for the user who created it and the specific user it has been shared with.
    • Format of the key shared with someone else should be <Shared with @sign>::<Created by @sign>

    Example:

    @bob:phone@alice

    Note: Above Key should be part of scan verb result for only @alice and @bob

    The owner of the secondary should be allowed to update or delete the value of a user key.

  4. Internal Key

    • Internal keys start with an underscore(_) and are not displayed in scan results. Internal keys can be looked up only by the owner of the secondary
  5. Cached Key

    • A cached key is a key that was originally created by another @sign user but is now cached on the Secondary Server of another user’s @sign as he/she was given permission to cache it.
    • A cached key should be listed in the scan verb result for the @sign user who cached it.

    • Format of the key shared with someone else should be cached:<Shared with @sign>::<Created by @sign>

    Example:

    cached:@bob:phone@alice

    The user who has cached the key should not be allowed to update the cached key.

    An @sign user who has created and shared the key should be allowed to update a cached key, and if the “autoNotify” config parameters is set to true, the updated value should be notified (please refer to the notify verb) and the cached key updated with the new value.

    If the user who originally shared the keys set the CCD (Cascade delete) to true, the cached key will be deleted when the original key is deleted.

Value

Text or binary values can be saved in a Secondary Server. The size of the value saved in a secondary is bound by the config parameter “maxBufferSize”.

A user should be made aware of this limitation by using the stats verb.

If a binary value is being saved on a Secondary Server, the “isBinary” attribute on the metadata should be set to true by the convention.

  1. Reference Value

    A Secondary Server should support referencing another key’s value.

    A reference value should be in the format “atsign://”.

    For example, ‘phone@bob(key)’ is 1234 (value). Now another key called altPhone@bob can refer to phone@bob by referencing it as altPhone@bob = atsign://phone@bob.

    When the user does a lookup on the key that contains a reference, the Secondary Server should return a fully resolved value.

  2. Metadata

    Metadata of a key should describe the following properties of the value being inserted.

    Meta AttributeAuto create?Description
    createdOnYesDate and time when the key has been created.
    createdByYes@sign that has created the key
    updatedOnYesDate and time when the key has been last updated.
    sharedWithNo@sign of the user with whom the key has been shared. Can be null if not shared with anyone.
    ttlNoTime to live in milliseconds.
    expiresOnYesA Date and Time derived from the ttl (now + ttl). A Key should be auto deleted once it expires.
    ttbNoTime to birth in milliseconds.
    availableFromYesA Date and Time derived from the ttl (now + ttl). A Key should be only available after availableFrom.
    isCachedNoTrue if the key can be cached by another @sign user.
    ttrNoTime in milliseconds after which the cached key needs to be refreshed. Ttr of -1 indicates that the key can be cached forever.
    refreshAtNoA Date and Time derived from the ttr. The time at which the key gets refreshed.
    ccdNoIndicates if a cached key needs to be deleted when the @sign user who has originally shared it deletes it.
    isBinaryNoTrue if the value is a binary value.
    isEncryptedNoTrue if the value is encrypted

2. Commit Log

A Secondary Server should record any create, update and delete operations in a commit log. The Commit Log should record these operations with a unique commit id so that users of the secondary can lookup operations that happened on or after a given commit id.

A Secondary Server should provide a way to compact the Commit Log based on time and size.

3. Access Log

A Secondary Server should record the following user actions: user login, user authentication and lookup. The Access Log should record these operations so that users of the secondary can retrieve various statistics such as the most visited @sign or most visited keys.

A Secondary Server should provide a way to compact the Access Log based on time and size.

4. Notification Log

A Secondary Server should record any notifications that have been received and sent. Please check the notify verb specification for details on how a notification should be sent.

A Secondary Server should provide a way to compact the Notification Log based on time and size.

Standard Keys

A Secondary Server should have the following standard keys:

KeyDescription
public:publickey@Public key used by other atsigns for encryption.
public:signing_publickey@Public key used on a pol handler to verify a signed challenge
@signing_privatekey@Private key used to sign a challenge on a pol request
:shared_key@Symmetric key used to encrypt/decrypt self atsign data

Configuration Parameters

A Secondary Server should honor the following configuration parameters.

KeyValid ValuesDescription
autoNotifytrue/falseIf set to true, a Secondary Server should automatically notify another @sign user when a key has been shared with him/her. Please refer to the notify verb spec for details.
bufferLimitNumber of bytesMaximum size of a value for a key that can be transferred to a Secondary Server
inbound_max_limitAn IntegerMaximum number of inbound connections that a Secondary Server can accept
outbound_max_limitAn IntegerMaximum number of outbound connections that a secondary can make to another Secondary Server
inbound_idle_time_millisTime in millisecondsMaximum time the inbound connection can be active
outbound_idle_time_millisTime in millisecondsMaximum time the outbound connection can be active.

Block List

A user of the Secondary Server should be able to decide who is allowed to connect to a Secondary Server. The config verb should be used to configure this. Once added, a Secondary Server should honor the list at the time of accepting new connections from an @sign user using the from verb.

Verbs

The from verb

Synopsis:

The from verb is used to tell a secondary whom you claim to be.

Following regex represents the syntax of the from verb:

Example:

r'^from:(?<@sign>@?[^@\s]+$)'

Response:

If the user who is trying to connect is the owner of the Secondary Server, then the from verb should respond with the following response.

key:<sessionId@sign:uuid>

If the user who is trying to connect is not the owner of the Secondary Server, then the from verb should respond with the following response.

proof:<sessionid>@<@sign>:<UUID>

If the user is not allowed to connect to the Secondary Server, then it should respond back with the following error and close the connection to the server.

error:AT0013-Connection Exception

Description:

The from verb is used to tell the Secondary Server what @sign you claim to be. With the from verb, one can connect to one’s own Secondary Server or someone else’s Secondary Server. In both cases, the Secondary Server responds back with a challenge to prove that you are who you claim to be. This is part of the authentication mechanism of the @protocol.

This authentication mechanism varies based on whether you are connecting to your own secondary (cram) or someone else’s secondary (pol).

OPTIONS:

<@sign> Required: Yes Description: @sign with which you are connecting to a Secondary Server.

The cram verb

Synopsis:

The cram verb is used to boostrap authenticate one’s own self as an owner of a Secondary Server. It is intended to be used once until a set of PKI keys are cut on the owner’s mobile device and from then on we use the pkam verb.

The following regex represents the syntax of the cram verb:

r'^cram:(?<digest>.+$)'

Response:

If the user gets the challenge right, the prompt should change to the @sign of the user.

<@sign>@

If the user gets the cram authentication wrong, then it should respond back with the following error and close the connection to the server.

error:AT0401-Client authentication failed

Description:

The cram verb follows the from verb. As an owner of the Secondary Server, you should be able to take the challenge thrown by the from verb and encrypt using the shared key that the server has been bound with. Upon receiving the cram verb along with the digest, the server decrypts the digest using the shared key and matches it with the challenge. If they are the same, then the secondary lets you connect to the Secondary Server and changes the prompt to your @sign.

OPTIONS:

<digest> Required: Yes Description: Encrypted challenge

The pol verb

Synopsis:

The pol verb is part of the pkam process to authenticate oneself while connecting to someone else’s Secondary Server. The term ‘pol’ means ‘proof of life’ as it provides a near realtime assurance that the requestor is who it claims to be.

Following regex represents the syntax of the pol verb:

r'^pol$'

Response:

If the user gets the challenge right the prompt should change to the @sign of the user.

<@sign>@

If the user gets the cram authentication wrong then it should respond back with the following error and close the connection to the server.

error:AT0401-Client authentication failed

Description:

The pol verb follows the from verb. ‘pol’ indicates another secondary that the user who is trying to connect is ready to authenticate himself. For example, if @bob is trying to connect to @alice, @bob would take the key and value from the proof response of the verb and create a public key and value which then can be looked up by @alice. After @alice looks up @bob’s secondary @alices secondary should change the prompt to @bob.

OPTIONS:

NA

The update verb

Synopsis:

The update verb is used to insert key/value pairs into a Key Store. An update can only be run by the owner of a Secondary Server on his/her own Secondary Server.

Following regex represents the syntax of the update verb:

r'^update:(?:ttl:(?<ttl>\d+):)?(?:ttb:(?<ttb>\d+):)?(?:ttr:(?<ttr>(-?)\d+):)?(ccd:(?<ccd>true|false):)?((?:public:)|(@(?<for@sign>[^@:\s]-):))?(?<atKey>[^:@]((?!:{2})[^@])+)(?:@(?<@sign>[^@\s]-))? (?<value>.+$)'

Response:

The Secondary Server should return the commit id from Commit Log if the update is successful.

data:<CommitId>

If the user provides the invalid update command, then it should respond with the following error and close the connection to the server

error:AT0003-Invalid Syntax

Description:

The update verb should be used to perform create/update operations on the Secondary Server. The update verb requires the owner of the secondary to authenticate himself/herself to the Secondary Server using from and cram verbs.

If a key has been created for another @sign user, the Secondary Server should honor “autoNotify” configuration parameter.

OPTIONS:

<ttl> Required: No Description: Time to live in milliseconds

<ttb> Required: No Description: Time to birth in milliseconds

<ttr> Required: No Description: Time to refresh in milliseconds.

-1 is a valid value which indicates that the user with whom the key has been shared can keep it forever and the value for this key won’t change forever.

<ccd> Required: No Description: A value of “true” indicates that the cached key needs to be deleted when the @sign user who has originally shared it deletes it.

<for@sign> Required: Yes (Not required when the key is a public key) Description: @sign of the user with whom the key has been shared

<@sign> Required: Yes Description: @sign of the owner

<value> Required: Yes Description: Value for the key

The update:meta verb

Synopsis:

The update:meta verb should be used to update the metadata of a key @sign user without having to send or save the value again.

Following is the regex for the update:meta verb

^update:meta:((?:public:)|((?<forAtSign>@?[^@\s]-):))?(?<atKey>((?!:{2})[^@])+)@(?<atSign>[^@:\s]-)(:ttl:(?<ttl>\d+))?(:ttb:(?<ttb>\d+))?(:ttr:(?<ttr>\d+))?(:ccd:(?<ccd>true|false))?(:isBinary:(?<isBinary>true|false))?(:isEncrypted:(?<isEncrypted>true|false))?$

Response:

The Secondary Server should return the commit id from Commit Log if the update is successful.

data:<CommitId>

If the user provides the invalid update meta command, then it should respond with the following error and close the connection to the server

error:AT0003-Invalid Syntax

Description:

The update:meta verb should be used to perform create/update operations on the Secondary Server. The update:meta verb requires the owner of the secondary to authenticate himself/herself to the Secondary Server using from and cram verbs.

The Secondary Server should allow creation of keys with null values. If a key has been created for another @sign user, the Secondary Server should honor “autoNotify” configuration parameter.

OPTIONS:

<ttl> Required: No Description: Time to live in milliseconds

<ttb> Required: No Description: Time to birth in milliseconds

<ttr> Required: No Description: Time to refresh in milliseconds.

-1 is a valid value which indicates that the user with whom the key has been shared can keep it forever and the value for this key won’t change forever.

<ccd> Required: No Description: A value of “true” indicates that the cached key needs to be deleted when the @sign user who has originally shared it deletes it.

<for@sign> Required: Yes (Not required when the key is a public key) Description: @sign of the user with whom the key has been shared

<@sign> Required: Yes Description: @sign of the owner

The lookup verb

Synopsis:

The lookup verb should be used to lookup the value shared by another @sign user.

The following is the regex of the lookup verb:

lookup:((?<operation>meta|all):)?(?<atKey>(?:[^:]).+)@(?<@sign>[^@\s]+)$

Response:

If the operation is not specified the Secondary Server should just respond back with the value saved by the user as is.

data:<value>

If the operation is to lookup the metadata only then the result should be wrapped in a JSON in the following format:

data:<Metadata in a JSON>

Example:

data: 
{
    "createdBy":"@bob",
    "updatedBy":"@bob",
    "createdAt":"2020-10-21 09:46:48.982Z",
    "updatedAt":"2020-10-21 09:46:48.982Z",
    "availableAt":"null",
    "expiresAt":"null",
    "refreshAt":"2020-10-21 09:46:58.982Z",
    "status":"active",
    "version":0,
    "ttl":null,
    "ttb":null,
    "ttr":10000,
    "ccd":false,
    "isBinary":false,
    "isEncrypted":false
 }

If the operation is to lookup the metadata and the data together then the result should be wrapped in a JSON in the following format:

data:<Value and Metadata in a JSON>

Example:

data:
{
	"key":"@alice:country@bob",
	"data":"USA",
	"metaData":
	{
	 "createdBy":"@bob",
       "updatedBy":"@bob",
       "createdAt":"2020-10-21 09:46:48.982Z",
       "updatedAt":"2020-10-21 09:46:48.982Z",
       "availableAt":"null",
       "expiresAt":"null",
       "refreshAt":"2020-10-21 09:46:58.982Z",
       "status":"active",
       "version":0,
       "ttl":null,
       "ttb":null,
       "ttr":10000,
       "ccd":false,
       "isBinary":false,
       "isEncrypted":false
     }
}

If the other Secondary Server on which the lookup needs to be performed is down then the secondary should return the following error and keep the connection alive.

error:AT0007-Secondary Server not found.

If the lookup command is not valid, then the Secondary Server should return the following error and close the connection:

error:AT0003-Invalid Syntax

For whatever reasons, If the handshake with another secondary fails, then the Secondary Server should return the following error:

data:AT0008-Handshake failure

Description::

The lookup verb should be used to fetch the value of the key shared by another @sign user. If there is a public and user key with the same name then the result should be based on whether the user is trying to lookup is authenticated or not. If the user is authenticated then the user key has to be returned, otherwise the public key has to be returned.

The plookup verb:

Synopsis:

The plookup verb enables to lookup the value of the public key shared by another @sign user.

Following is the regex of the plookup verb:

^plookup:((?<operation>meta|all):)?(?<atKey>[^@\s]+)@(?<@sign>[^@\s]+)$

Response:

The Secondary Server should return the value or metadata or the value and metadata together based on the option specified.

The response structure should be exactly the same as the lookup verb.

If the other Secondary Server on which the lookup needs to be performed is not available, then the secondary should return the following error and keep the connection alive.

error:AT0007-Secondary Server not found.

If the lookup command is not valid, then the Secondary Server should return the following error and close the connection:

error:AT0003-Invalid Syntax

Description::

The plookup verb should be used to fetch the value of the public key shared by another @sign user.

The llookup verb

Synopsis:

The llookup verb should be used to look up one’s own secondary and this should return the value as is (i.e. without any resolution).

The Following is the regex of the llookup verb:

^llookup:((?<operation>meta|all):)?(?:cached:)?((?:public:)|(@(?<for@sign>[^@:\s]-):))?(?<atKey>[^:]((?!:{2})[^@])+)@(?<@sign>[^@\s]+)$

Response:

The Secondary Server should return the value or metadata or the value and metadata together based on the option specified.

The response structure should be exactly the same as the lookup verb.

If the other Secondary Server on which the lookup needs to be performed is down then the secondary should return the following error and keep the connection alive.

error:AT0007-Secondary Server not found.

If the lookup command is not valid, then the Secondary Server should return the following error and close the connection:

error:AT0003-Invalid Syntax

Description::

The llookup verb should be used to fetch the value of the key in the owners secondary store as is without resolving it. For example if a key contains a reference as a value, the lookup verb should resolve it to a value whereas llookup should return the value as is.

Example:

If phone@bob is “1234” and altphone@bob is “atsign://phone@bob”, then lookup of altphone@bob should return “1234” whereas llookup of altphone@bob should return “atsign://phone@bob”.

The pkam verb

Synopsis:

The pkam verb is used to authenticate one’s own self as an owner of a Secondary Server using a PKI style authentication.

Following regex represents the syntax of the pkam verb:

^pkam:(?<signature>.+$)

Response:

If the user gets the challenge right, the prompt should change to the @sign of the user.

<@sign>@

If the user gets the pkam authentication wrong then it should respond back with the following error and close the connection to the server.

error:AT0401-Client authentication failed

Description:

The pkam verb follows the from verb. As an owner of the Secondary Server, you should be able to take the challenge thrown by the from verb and encrypt using the private key of the RSA key pair with what the server has been bound with. Upon receiving the cram verb along with the digest, the server decrypts the digest using the public key and matches it with the challenge. If they are the same then the secondary lets you connect to the Secondary Server and changes the prompt to your @sign.

OPTIONS:

<digest> Required: Yes Description: Encrypted challenge

The stats verb

Synopsis:

The stats verb should be used to get the statistics of an atsign.

Following is the regex of the stats verb

stats(?<statId>:((?!0)\d+)?(,(\d+))-)?

Response:

If the user gives stats all the statistics will be returned as JSON. Following statistics are provided:

  1. activeInboundConnections
  2. activeOutboundConnections
  3. lastCommitId
  4. secondaryStorageSize
  5. topAtSigns
  6. topKeys

Example:

data: [{"id":"1","name":"activeInboundConnections","value":"1"}, {"id":"2","name":"activeOutboundConnections","value":"0"}, {"id":"3","name":"lastCommitID","value":"1"}, {"id":"4","name":"secondaryStorageSize","value":12560}, {"id":"5","name":"topAtSigns","value":{"@bob":1}}, {"id":"6","name":"topKeys","value":{"publickey@alice":1}}]

Individual statistics can be retrieved using the respective Id.

@alice@stats:1
data: [{"id":"1","name":"activeInboundConnections","value":"1"}]

The sync verb

Synopsis:

The sync verb enables to synchronize the keys between the local Secondary Server and remote Secondary Server.

Following is the regex:

sync:(?<from_commit_seq>[0-9]+$|-1)

Response:

The sync verb returns a json array of the commit entries from the given commit id to the current commit id. Further, The sync verb accepts -1 as argument which returns all the commit entries.

data:[{"atKey":"@bob:phone@alice","operation":"+","opTime":"2020-10-26 11:57:43.732","commitId":0,"value":"12345","metadata":{"ttr":"36000000","ccd":"false"}},
{"atKey":"@bob:shared_key@alice","operation":"-","opTime":"2020-10-26 09:44:54.382219Z","commitId":1}]

The notify verb

The notify verb enables us to notify the atsign user of some data event.

The Following is the regex for the notify verb

notify:((?<operation>update|delete):)?(ttl:(?<ttl>\d+):)?(ttb:(?<ttb>\d+):)?(ttr:(?<ttr>(-)?\d+):)?(ccd:(?<ccd>true|false):)?(@(?<forAtSign>[^@:\s]-)):(?<atKey>[^:]((?!:{2})[^@])+)@(?<atSign>[^@:\s]+)(:(?<value>.+))?

Response:

When a key is notified successfully, returns

data:success

Description:

When an atsign user notifies the key to another atsign user, an entry has to be created in received notifications list on the user who has shared the key and an entry has to be created in sent notifications list on the user to whom the key is to be notified. When auto notify is set to true, when a key is created/updated and deleted notification is triggered to another atsign user.

Notify List

Synopsis:

Notify list returns a list of notifications.

Following is the regex

notify:(list (?<regex>.-)|list$)

Response:

If the user is the owner, returns a list of received notifications. If a user is pol authenticated user, returns a list of sent notifications

data:[{"id":"0e5e9e89-c9cb-423b-8972-8c5487215990","from":"@alice","to":"@bob","key":"@bob:phone@alice","value":12345,"operation":"update","epochMillis":1603714122636}]

The monitor Verb

Synopsis:

The monitor verb streams received notifications.

Following is the regex

^monitor$|^monitor ?(?<regex>.-)?)$

Response:

Returns a stream of notifications.

@alice@monitor
notification: {"id":"773e226d-dac2-4269-b1ee-64d7ce93a42f","from":"@bob","to":"@alice","key":"@alice:phone@bob","value":null,"operation":"update","epochMillis":1603714720965}

Description:

The monitor verb accepts an optional parameter to filter the notifications by passing filter criteria as regex to monitor verb.

Error Codes

Error CodeError MessageDescription
AT0001Server exceptionException occurs when there is an issue while starting the server.
AT0002DataStore exceptionException occurs during keystore operations (GET/PUT/DELETE).
AT0003Invalid syntaxException occurs if we give any invalid command to the server.
AT0004Socket errorException occurs when socket connection to secondary cannot be established.
AT0005Buffer limit exceededThis exception occurs when input/output message size reaches the maximum limit configured in the server.
AT0006Outbound connection limit exceededException occurs when the number of open connections to other secondaries reaches the maximum limit configured.
AT0007Secondary Server not foundException occurs when a secondary tries to connect to another secondary which is not available in the root directory or not yet instantiated.
AT0008Handshake failureThis exception is for any exception during the handshake process of two secondaries.
AT0009UnAuthorized client in the requestUnAuthorized Exception

will occur when an unsuccessful handshake happens between two secondaries.

AT0010Internal server errorThis is for any server related errors.
AT0011Internal server exceptionThis exception is used for any server related exceptions.
AT0012Inbound connection limit exceededThis exception will occur when the number of active clients reaches the maximum limit configured.
AT0401Client authentication failedThis exception occurs when client authentication fails or client tries to execute any verb which needs authentication before successful authentication.
AT0013Connection ExceptionThis will occur when a blocked user tries to connect to the secondary.
AT0014Unknown AtClient exceptionThis exception will be thrown while performing any operations(Get/update/delete) using AtClient SDK.
AT0015Key not foundThis exception will be thrown when the key is not available for encryption/decryption.
AT0021Unable to connect to secondaryThis exception will occur when we are unable to connect to secondary.

Glossary

@protocol (Pronounced, at protocol)

@sign (Pronounced, at sign) @sign is a unique name that a user gets when enrolled with @sign.com

Root Server

Secondary Server

Verb

Public Key

Private Key

Shared Secret

Default Keys

Key

Value

Metadata

Commit Log

Access Log

2 - How to get started with the @platform

The fastest way to get started developing your privacy-first app on the @platform

The @platform was open-sourced in November of 2020 and we’ve been working hard to make your onboarding experience as smooth as possible ever since.

We’re excited to help you get your very own @platform environment up and running!

Prerequisites

You will need Flutter/Dart installed on your machine. If you haven’t already, please follow the “Get started” steps on flutter.dev before you proceed. Flutter works best with Android Studio, but you can also use IntelliJ or Visual Studio Code as your IDE.

Flutter

Why did we choose Flutter? Here are some of our favorite reasons:

• Beautiful User Interface that allows you to control every pixel in your app, bring your brand to life, and provide flawless People experiences.

• Apps directly compile to native ARM code for screaming fast and efficient project builds housing buttery-smooth animations that allow GPU acceleration.

• Hot Reload. Make an edit to your code and Flutter will update your source code files and automatically rebuild the widget tree, allowing you to see your edits almost immediately. No more rebuilding your application time and time again.

• It’s free and open-source, just like the rest of the @protocol, and there are countless numbers of packages on pub.dev that any developer is free to use. The Flutter community is growing fast and would love to welcome you!

Android Studio

Android Studio is an incredible Integrated Development Environment (IDE) you can use to create projects for Android devices, and to ease this process,it allows you set up an Android Virtual Device (or AVD). If you’re looking for an easy IDE to get started on, this is the one we recommend. Most of our code, documentation, and tutorials are created with Android Studio, so you’ll feel right at home!

Important Links for Android Studio

  • Download Android Studio here
  • Read an article on how to set up an AVD here

IntelliJ

IntelliJ is another commonly used IDE. It has a similar feel to Android Studio and is comparable to the other two IDE’s recommended here.

Important Links for IntelliJ

  • Download IntelliJ here

Visual Studio Code

Visual Studio Code, when compared to IntelliJ and Android Studio, is the most customizable with a seemingly endless number of programming languages to utilize. Developers commonly call this IDE ‘VS Code’ (who has time to say entire words anyway?). If you have watched our tutorials on atsign.dev, you’ll notice that VS Code is the other IDE of choice with our devs!

Important Links for Visual Studio Code

  • Download Visual Studio Code here

Docker Desktop

If you wish to develop offline, you will also need to install Docker Desktop on your machine. Using Docker Desktop allows you to run the full @platform stack locally, with no dependence on Internet connectivity, we call this the Virtual Environment.

Where should I go next?

There are three ways to get going with your journey on the @platform. You may choose any of the three options listed below depending on your interest and particular needs.

If you just want to get going and fast, then the best solution is to get some free @signs and start coding. Here we will show you how to get a couple of free @signs and activate them. This option uses The @ Companies infrastructure to host a secondary server microservice for each @sign you activate.

Dess (distributed edge secondary server) is the right place to start if you would like to run your own infrastructure, for your @sign. Or perhaps you are developing an IoT solution and would like to see the log files of the secondary server microservice, then using dess, is the perfect starting place.

(Option 3) The Virtual Environment

Recommended for those offline moments or if you want to be completely independent. The virtual environment (VE) provides all the components of the @platform in a single docker image. Complete with full control and logging of everything, VE requires no Internet connection and comes with some predefined @signs.



( Please note that all the logos listed on this page are registered trademarks of the respective products.We have used them here only for reference purposes.)

2.1 - Option 1 : Set up the @platform with free @signs

Create and run your own @platform with free @signs

Getting @signs and keys.

Your first step is to get a couple of @signs, it is best to get at least two, so you can experiment with sharing end-to-end encrypted data across the @platform.

There are two methods to get @signs.

The first

Go to atsign.com and clicking Get an @sign. If you go this route then you have more influence on your free @sign or pay for one of your choosing. Once you have your @signs, do not forget to activate them.

activate @sign

Activating creates a microservice (we call the secondary server) and once that is spun up on The @ Company infrastructure you will see a QR-Code to scan with an @ enabled application.

activated @sign

The pairing consists of your device creating cryptographic keys and sharing the public keys to the secondary server, you will be asked to store your private keys. Storing your keys is vitally important as only you have the keys.

The second

The experience of getting a @sign via the website is great for developers as you have advanced options available, to reset @signs and to point your @sign to your own infrastructure. For getting people onboarded quickly, a better experience would be to get a free @sign within the app itself, this is option 2.

generate @sign

The onboarding widget together with an API key provides a button marked “Generate Free @sign”.

generate @sign-pair

When selected a number of free @signs given to chose from, once selected it is quickly activated, then once again you will be asked to store the cryptographic keys for the @sign.

Once you have your @signs and keys

You are ready to start using the @platform! We have a number demo apps that are constantly being updated, feel free to fork or clone and try them. There is also another nice app in development by xavierchanth which is a chat app using the @platform. It is a nice example to follow as it uses the contacts combined with the at_chat_flutter widgets to create a simple chat app between @signs.

ChitCh@t

Each @ enabled application will ask you once for your @sign and then your keys, so it can synchronize with your secondary server. This means you might like to store your keys on a personal network drive or service (e.g. gdrive/idrive/onedrive) so you can connect other @ enabled apps to your @sign easily. Remember not to share and protect your keys.

Other widgets and the @platform/@protocol source code

We have an ever-growing number of widgets on pub.dev The @plaform and the @protocol are open source projects on GitHub. If you see something missing, or not working let us know or better still contribute with a PR!

2.2 - Option 2: Setup your own secondary server with dess

Create and run your own @platform secondary server with dess

1. What is dess?

dess is the self-hosted option for secondary servers, and a great tool for developers to debug their applications! You can run several secondary servers on a single instance of dess, as each secondary scales to use 6MB of ram or less.

dess is an acronymn for:

d. Distributed
e. Edge
s. Secondary
s. Server

2. How to get started

There are two parts to setting up dess:

  1. First time setup (run once)
  2. Setup an @‎sign (run for each @‎sign)

3. First Time Setup

Get a server

First get yourself a microserver to run dess on.

We recommend AWS, GCP, or IONOS for hosting.

1 Core + 1 GB is more than enough to run dess comfortably.

Install dess on the server

dess will install everything you need to get up and running.
Run the following command to install dess:

curl -fsSL https://getdess.atsign.com | sudo bash

Alternatively, if you would like to save the installation script to your machine:

curl -fsSL https://getdess.atsign.com -o getdess.sh
sudo bash getdess.sh

The script will be saved as getdess.sh

Setup a domain for your server

If you don’t have a domain available you will have to purchase one to continue.

Once you have a domain available, set an A record pointing to the IP of your server.

For example:

Domain: example.com
Server IP: 123.123.123.123

Example A record:

A    dess    123.123.123.123

You may replace “dess” with any valid value for a subdomain.
In this example, my fully qualified domain name (fqdn) is:

dess.example.com

Once you have completed these steps, please move on to setting up your secondary server!

4. Setup a secondary server

On my.atsign.com/dashboard

  1. Go to “My @‎signs.”
  2. Select “Manage” for the @‎sign you would like to setup.
  3. Open “Advanced Settings”.
  4. If the atsign is activated, follow the steps to reset it. (Warning: this will erase your data!)
  5. Under “settings” enter the fully qualified domain name from initial setup.
  6. Enter an unused port number.
  7. Press “Activate”

On your dess server

dess will show you the steps to setup a secondary server.

sudo dess-create
> Usage sudo dess-create <@‎sign> <fqdn> <port> <email> <service>
> Example sudo dess-create @‎bob bob.example.com 6464 bob@‎example.com bob

Arguments

@‎sign: The @‎sign you want to setup.

fqdn: Fully qualified domain name to use for dess.
(The same as entered in your atsign.com dashboard )

port: The port to use for dess.
(The same as entered in your atsign.com dashboard)

email: An email you own to sign the certificates with.

service: A name for the docker service.

5. OS Support

DistributionVersionx86arm64armv7
Amazon Linux2
Centos7,8
Debian10
Raspbian10
Rocky Linux8
Ubuntu20.04-21.04

6. dess Setup Guides

If you are ready to get started, please check to see if we have a specific guide available for your platform of choice.

We have guides available for the following platforms:

7. Tips & Tricks

Oops! I forgot to save my QR code!

Don’t worry! dess includes a command to recover QR codes.
Simply run the following:

dess-reshowqr <@‎sign>

Debugging Applications with Dess

dess runs as a docker swarm, to debug an application first run the following:

docker service ls

Docker will list the services running:

ID             NAME                   MODE         REPLICAS   IMAGE                          PORTS
b61ty3y5g41a   secondaries_shepherd   replicated   1/1        mazzolino/shepherd:latest
ex2d0kmiqinn   wolverine_secondary    replicated   0/1        atsigncompany/secondary:dess   *:6464->6464/tcp

For example, I have the service called “wolverine_secondary” running.
To debug this secondary using docker:

docker service logs -f <service_name>
# OR
docker service logs -f wolverine_secondary

While this is running, you will be able to see the secondary in action.

2.3 - Option 3 : Set up the @platform virtual environment

Create and run your own @platform virtual environment on your machine

Why is there a virtual environment to set up, and what does it do? Jumping directly into the deep end and creating projects on top of the @platform can be overwhelming, so we have made a simple way for you to run the @platform from your machine.

First, why is there a virtual environment to set up, and what does it do?

The virtual environment has two main benefits: you can monitor the status of your test secondary servers (by visiting localhost:9001), and you can bypass the traditional onboarding process completely.

Jumping directly into the deep-end and creating projects on top of the @platform can be overwhelming for some. To combat this overwhelming feeling, we have created a simple way to have you run the @protocol from your very own machine!

This will allow you to run both a root server and secondary servers of testable @signs. We have created demo apps that go over specific verbs and methods to help you get oriented.

Setup Virtual Environment

Windows

Your machine’s BIOS may already have virtualization enabled. You can check here.

Loopback adapter

Install the Microsoft loopback adapter and configure it. Here’s a video showing how:

Start up the at_virtual_environment

Run cmd and enter the following commands. You can run cmd by using the Windows key and the r key then typing cmd.

mkdir ve
cd ve
curl -L atsign.dev/curl/virtualenv-compose-vip.yaml -o docker-compose.yaml

Now you are ready to spin up the docker containers:

docker-compose up -d

Okay, you’re up. Now you can check the http://localhost:9001/.

Not sure what to do now? Try here!

MacOS

Configure Network Adapter

Open the Terminal window and enter this command. This permanently puts the Virtual IP address in place. You only need to run this once!

sudo curl -L atsign.dev/curl/atloop.plist -o /Library/LaunchDaemons/atloop.plist && \

Once you enter the above command, an arrow “>” should show up to enter the next line:

sudo launchctl load /Library/LaunchDaemons/atloop.plist

The command line may ask you to enter your password. Go ahead and fill it in if this happens.

Start up the Virtual Environment

Make a new directory called “ve” and run the curl command inside of it:

mkdir ve
cd ve
curl -L atsign.dev/curl/virtualenv-compose-vip.yaml -o docker-compose.yaml

Now you are ready to spin up the docker containers:

docker-compose up -d

Not sure what to do now? Try here!

Linux

Configure Network Adapter

Open the Terminal window and enter this command. This permanently puts the Virtual IP address in place. You only need to run this once!

curl -L atsign.dev/curl/rc.local -o setvip.sh
sudo ip addr add 10.64.64.64/32 dev lo
sudo nano /etc/rc.local

If the file “/etc/rc.local” is empty, then add the contents of the file “setvip.sh” to /etc/rc.local”. If rc.local already has content, then add the line “ip addr add 10.64.64.64/32 dev lo” above any lines that say “exit 0”. This will ensure that the virtual IP is in place even after a reboot. Ensure the permissions are correct with the following command:

sudo chmod 744 /etc/rc.local

Start up the Virtual Environment

Make a new directory called “ve” and run the curl command inside of it:

cd ~
mkdir ve
cd ve
curl -L atsign.dev/curl/virtualenv-compose-vip.yaml -o docker-compose.yaml

Now you are ready to spin up the docker containers:

docker-compose up -d

Okay, you’re up. Now you can check the http://localhost:9001/.

Not sure what to do now? Try here!

To Pull Latest Virtual Environment Version

docker-compose down
docker-compose pull
docker-compose up -d

Congratulations! You’ve set up your virtual environment and can now experiment with the hello_world app. Now you can start building your very own privacy-conscious apps.

When writing code, the only change needed to run in the virtual environment is changing the ROOT_DOMAIN to point to vip.ve.atsign.zone. The production value is root.atsign.org.

To Authenticate with Demo QR Codes

You will need the PKAM and CRAM Key QR codes in order to properly authenticate your testable atsigns.

You will find the group of these keys on our GitHub here

Where should I go next?

Give your users next steps from the Overview. For example:

  • Sample Apps: See apps that show off the power of the @platform on your own machine!

2.4 - Create your own @platform project

Taking one step closer to developing your privacy-first app on the @platform

If you’ve ever used Flutter and have gone through the process of creating a new Flutter Application Project, you’re more than likely aware of what a fresh application should look like. We’ve decided to create our own toolkit here on the @platform to make your ‘Getting Started’ experience that much smoother!

As of now, the only way to use this toolkit is via the command line. In the future we plan on supporting IDE extensions, be sure to check for when those come out!

Getting started via the command line

at_app is our command line toolkit that can be installed via pub. Behind the scenes, it uses flutter create in order to create your project, and it completes the necessary steps to setup your @platform application for you!

Install the command line toolkit

flutter pub global activate at_app

Verify your system PATH variable

  • When you run the command above, it may prompt you that the pub cache bin is missing from the system PATH variable.
  • The prompts will tell you the appropriate steps to add it to the PATH variable.
  • Please complete those steps before continuing.

Run the program

Note for Windows users

  • In the following commands you will see the at_app command, please replace it with at_app.bat.

Command Format

at_app create [...options] path/to/your/project

In practice the command looks like this:

at_app create --namespace=myatsign myproject

In addition to the same options available for flutter create, at_app create includes three new ones to help you automatically configure your application.

FlagShorthandDescriptionValue
-‎-namespace-nThe @protocol app namespace to use for the application.(defaults to “‎”)
-‎-root-domain-rThe @protocol root domain to use for the application.[prod (default), ve]
-‎-api-key-kThe api key for at_onboarding_flutter.(defaults to “‎”)

Note: at_app create does not include --template, --sample, or --list-samples (Coming soon).

Okay great, we know what the flags are but what do they do?

Namespace

The namespace is the most important flag to include when creating your application.

When storing keys on the secondary server, the namespace is used to filter the data produced by your app from the other @platform applications. To create a namespace for your app, make sure to register an @sign from atsign.com and use that as your namespace. By owning the @sign, you can ensure that you also own the namespace.

You can specify the namespace with --namespace=YOUR_NAMESPACE_HERE.

Root Domain

By default the root domain is set to prod (production). In the production domain, you can use real @signs to test your application.

Alternatively you can specify --root-domain=ve in the command to choose the virtual environment, and test with those @signs instead.

API Key

When you are ready to publish your application, you can request an api-key for the Onboarding Widget. This api-key will authorize your app when attempting to generate a free @sign within the widget.

You can specify this with --api-key=YOUR_API_KEY_HERE.

Updating your configuration

If you would like to update your environment at any point in time, it is safe to do so. Just specify the options you would like to change.

Warning

  • Do not use the --overwrite flag when doing so, or it will overwrite the changes you have made to lib/main.dart

Congratulations!

You have successfully created your first @platform application!

Time to start coding!

Where should I go next?

We recommend checking out the demo apps that we have to offer! Reviewing these will greatly assist in your understanding of verb implementation on the @platform! It would also be a good idea to check out our @dev program which will show you how to have your app @certified and released to the market!

  • Sample Apps: See apps that show off the power of the @platform on your own machine!

  • @dev Program: Read up on how to get your @certification and go to market with your privacy-focused application!

3 - Architecture of the @platform

The components of the @platform architecture

The picture below provides a great way to visualize just how much thought has gone into making the life of a developer on the @platform that much easier! Functional Architecture

If you’re wondering what the difference between what the @platform consists of and what the @protocol consists of, look no further!

The @platform, which has been created on top of the @protocol consists of three major segments of developer tools. These segments consists of; Services, Libraries, and Widgets

3.1 - Services provided by the @platform

Important services provided by the @platform

Data Caching & Encryption

Data that others have shared with an @sign owner is cached on the @sign owner’s device’s local keystore if permitted.

Learn more

Notification

Notification is a mechanism which enables an @sign to share data with another @sign. The data shared is end to end encrypted. @sign owner can query the status of the notification.

Learn more

Onboarding

The onboarding process is responsible for creating the authenticating keys for a new @sign or retrieving the authenticating keys of an existing @sign from the keys file provided by the @sign owner. It also synchronizes the data between mobile apps and the cloud secondary server.

Learn more

Peer-to-Peer Streams

Streams enable transferring of files between the @sign’s through a secure and dedicated socket between sender and receiver. The files can be a text documents, images, audio-video files etc. The stream transfers are end to end encrypted.

Learn more

Persistence

The persistence defines the interfaces on how the data in @protocol is stored.

Learn more

Synchronization

Synchronization is a process to keep the data in mobile apps and @sign server identical.

Learn more

3.2 - Libraries

Find the list of libraries the @platform has to offer here!

at_persistence_spec

at_persistence_spec is the Specification for the persistence layer implementation of @protocol development.

Learn more

at_commons

A library of Dart and Flutter utility classes that are used across other components of the @‎platform.

Learn more

at_common_flutter

A Flutter package to provide common widgets used by other @‎platform Flutter packages.

Learn more

at_client

The at_client library is the non-platform specific Client SDK which provides the essential methods for building an app using the @protocol.

Learn more

at_lookup

A Dart library that contains the core commands that can be used with a secondary server (scan, update, lookup, llookup, plookup, etc.). This library is also used for building command line tools.

Learn more

at_persistence_secondary_server

A Dart library with the implementation classes for the persistence layer of the secondary server.

Learn more

at_server_status

A Dart library that provides a means to check on the status of the @‎root server as well as the secondary server for any particular @‎sign.

Learn more

at_utils

A Dart library that contains various utility classes such as atSign, atmetadata, configuration, and logger.

Learn more

at_backupkey_flutter

A flutter plugin project for saving backup key of any @sign that is being onboarded with @protocol apps. Backup key can used to authenticate in any @protocol apps.

Learn more

at_onboarding_flutter

A Flutter plugin project for onboarding any @‎sign in @‎platform apps with ease. Provides a QRscanner option and an upload key file option to authenticate.

Learn more

at_client_mobile

A Flutter extension to the at_client library which adds support for mobile, desktop and IoT devices.

Learn more

at_contacts_flutter

A Flutter plugin project to provide ease of managing contacts for an @‎sign using @p‎latform.

Learn more

at_chat_flutter

A Flutter package to provide chat feature between @signs using the @platform.

Learn more

at_demo_data

A Dart library that contains test data, testable @‎sign credentials and demo environment variables that can be used for writing demo apps and testing with the local test environment.

Learn more

at_contacts_group_flutter

A Flutter plugin project to provide group functionality with contacts using @‎platform.

Learn more

at_location_flutter

A Flutter plugin project to share locations between two @‎signs and track them on OSM (OpenStreetMap).

Learn more

at_utf7

Provides methods to encode/decode strings to/from the utf7 format as defined in rfc 2152

Learn more

at_contact

A Dart library for managing contact data that developers can use for their applications.

Learn more

at_events_flutter

A Flutter plugin project to manage events (time, place and attendees) using the @‎platform.

Learn more

at_base2e15

binary-to-text encoding schemes that represent binary data in an unicode string format, each unicode character represent 15 bits of binary data.

Learn more

at_follows_flutter

A Flutter plugin project that provides a basic social “follows” functionality for any @‎sign. Provides a list of @‎signs that follow you (followers) as well as the @‎signs that you follow (following) with the option to unfollow them.

Learn more

at_server_spec

A Dart library containing abstract classes that defines what implementations of the root and secondary servers are responsible for.

Learn more

at_map

A new Flutter plugin.

Learn more

3.3 - The @platform widgets

Build your app more quickly with these @platform widgets

The Onboarding Widget

Onboarding for the first time with the @platform isn’t as simple as choosing your @sign from a dropdown menu and clicking “Login” (after all, how would the application know where to retrieve your authentication keys from a given @sign?).

Implementing onboarding from scratch would be painstakingly difficult. Not only would you have to code the PKAM logic, but you would also have to build your own QR code scanner to extract the CRAM (Challenge-Response Authentication Mechanism) key from your @sign’s QR code generated on our website! The @ Company realized this very quickly, so we developed the at_onboarding_flutter widget to help developers who want to build production-level apps that onboard real @signs (AKA @signs that you get from our .com site).

Learn more about the onboarding widget here!

Use this package as a library

at_onboarding_flutter: ^1.0.0+4

The “Onboarding” widget is very handy in that you do not need to call the “onboard” or “authenticate” methods from the service file of the application to get it running. Instead, it will ask us to specify the following parameters (descriptions for each parameter are written in the comments):

class Onboarding {
 ///Required field as for navigation.
 final BuildContext context;

 ///Onboards the given [atsign] if not null.
 ///If [atsign] is null then it takes the atsign from keychain.
 ///If [atsign] is empty then it directly jumps into authenticate 
 ///without performing onboarding. (or)
 ///If [atsign] is empty then it just presents pairAtSign screen 
 ///without onboarding the atsign. (or)
 ///Just provide an empty string for ignoring existing atsign in 
 ///keychain or app's atsign.
 final String atsign;

 ///The atClientPreference [required] to continue with the onboarding.   
 ///atClientPreference is an instance of a class in the  
 ///at_client_mobile library that stores a number of important 
 ///attributes like the namespace of the application, the CRAM key of  
 ///an @sign, the root domain we want the project to communicate 
 ///with, and so on. 
 final AtClientPreference atClientPreference;

 ///The root domain for our project. By default, the plugin connects 
 ///to [root.atsign.org] to perform onboarding.
 final String domain;

 ///The color of the screen to match with the app's aesthetics. 
 ///default it is [black].
 final Color appColor;

 ///If logo is not null, then it displays the widget on the left side 
 ///of appbar. Else, it displays nothing.
 final Widget logo;

 ///Function returns atClientServiceMap on successful onboarding along 
 ///with onboarded @sign. Assign these returned values to the relevant 
 ///variables in your project’s service file.
 final Function(Map<String, AtClientService>, String) onboard;

 ///Function returns error if onboarding fails for an @sign.
 final Function(Object) onError;

 ///After successful onboarding, the app will be redirected to this 
 ///screen if it is not null.
 final Widget nextScreen;

 ///After the first successful onboarding, the app will get redirected 
 ///to this screen if not null.
 final Widget fistTimeAuthNextScreen;

 final AtSignLogger _logger = AtSignLogger('At Onboarding Flutter');

 Onboarding({Key key,
   @required this.context,
   this.atsign,
   @required this.onboard,
   @required this.onError,
   this.nextScreen,
   this.fistTimeAuthNextScreen,
   @required this.atClientPreference,
   this.appColor,
   this.logo,
   this.domain})
 ...
}

To see an actual implementation of the onboarding widget, let’s revisit the _login function in the at_hello_world app with some updated code:

/// Return an “Onboarding” widget that walks the individual through
/// the onboarding procedure for any real @sign.
_login() async {
 return Onboarding(
     context: context,
     /// Ensure that the “root” attribute is assigned to 
     /// “root.atsign.org” 
     domain: AtConfig.root
     atClientPreference: await 
        _serverDemoService.getAtClientPreference(),
     appColor: Color.fromARGB(255, 240, 94, 62),
     onboard: (atClientServiceMap, atsign) {
       _serverDemoService.atClientServiceMap = atClientServiceMap;
       _serverDemoService.atSign = atsign;
     },
     onError: (error) {
       print(error);
     },
     /// Remove the constructor in HomeScreen. You can call the @sign
     /// with the getAtSign() method in the service file. 
     nextScreen: HomeScreen(),
 );
}

All of the parameters in the “Onboarding” widget can be populated very easily with either methods from the project’s service file (e.g. getAtClientPreference()) or special variables from the app itself (e.g. context). “Onboarding” is capable of handling all instances of an @sign (e.g. a particular @sign does not exist, a particular @sign exists but needs to be paired with a QR code to the device, a particular @sign exists and its keys are already in the device’s keychain manager). By using this widget, what would have taken several screens and many lines of code can be completely bypassed with a single return statement!

That’s all for the “Onboarding” widget. Before moving on from this subsection, we highly recommend implementing the widget in your own application and onboarding a real @sign to understand its intended user journey. If you’re interested, these are the steps to implement the “Onboarding” widget in the at_hello_world project:

Update your Android Studio, Flutter SDK, and Dart SDK to their latest versions. Place the at_onboarding_flutter dependency in pubspec.yaml. Follow the setup procedure for the “Onboarding” widget in the “AndroidManifest” (android -> app -> src -> main -> AndroidManifest.xml) and “gradle” file (android -> app -> build.gradle) of the at_hello_world project. You may also need to update the “classpath” of the android gradle build tool to 3.5.4 (this can be done by going to android -> gradle -> build.gradle and editing the first classpath in the “dependencies” brackets). This must be completed in order to set up the permission for the QR code scanner to access your camera. Find those steps on the pub.dev site for at_onboarding_flutter here. Get a free @sign from atsign.com. Generate its QR code, and drag/drop the created file directly into the emulator. Confirm that the QR code image appears in the “Files” or “Drive” app of the emulator you’re using (assuming that it is an Android emulator). In “at_conf.dart”, update the “root” variable from ‘vip.ve.atsign.zone’ to ‘root.atsign.org’. This ensures that the project points to the domain that is used in production as opposed to the one for the virtual environment. Replace the existing code in the login() function with what we wrote above. Double-check that no errors arise (you’ll likely have to tweak the names of a couple of methods in the service file, because some of them begin with the “” private designation). Fire the app on your emulator. Although the dropdown menu will still appear (since we didn’t change any of that code), we will not be authenticating with any of the testable @signs. If you’d like, simply remove the “DropdownButton” widget so that we can eliminate the list of testable @signs. Click on the “Login” button. Assuming that you haven’t previously authenticated with a real @sign, the “Onboarding” widget should prompt you with a request to upload your QR code. Upload the QR code you saved onto the emulator earlier and wait for the authentication to complete. If no errors form, the “Onboarding” widget should take you seamlessly to the “Home” screen, where you can add & retrieve key/value pairs directly from your very own secondary server! The next time you authenticate (i.e. restart the application), the “Onboarding” widget should detect the authentication keys placed in your device’s keychain manager and guide you directly to the “Home” screen.

The Chatting Widget

One of the many things you can do after successfully authenticating an @sign is providing one-to-one text messaging! To do this, you’ll need the at_chat_flutter widget.

The at_chat_flutter widget offers a messaging experience that is unique to the @platform. In a traditional messaging application, your texts are stored in a remote database and the person you’re pinging pulls the texts from there (a bit unsettling if you think about it). Of course, there is no such thing as a remote database in the @platform, so we had to be a bit clever coming up with a messaging scheme. In a nutshell, your text messages are not “sent” but rather “shared” with another @sign. All your texts are stored securely in your secondary server and never leave; if you decide to send a message to someone, that person is given permission to view that text via the notify verb, which will be covered in the next section on advanced @platform verbs.

Learn more about the chatting widget here!

Use this package as a library

at_chat_flutter: ^1.0.1

Although this messaging dynamic might sound a bit involved, set up is quite easy! To get a feel for using the “Chatting” widget, it’s best to follow along with the at_chats demo application.

The general flow of all @platform widgets is onboarding an @sign => initializing the service object => creating the actual widgets. Assuming we’ve already onboarded an @sign, let’s look at the steps to initialize our chat service:

(The following code snippets are taken directly from at_chats. While there will be explanations, don’t worry too much about all the variables!)

getAtSignAndInitializeChat() async {
 /// In the at_chats app, the onboarded @sign is displayed at the top 
 /// of the Second Screen. We set that @sign to [currentAtSign].
 String currentAtSign = await clientSdkService.getAtSign();
 /// Set [activeAtSign], which is the variable that gets displayed, to
 /// [currentAtSign] using setState(() {}).
 setState(() {
   activeAtSign = currentAtSign;
 });
 /// Initialize a List of Strings called [allAtSigns] that we will 
 /// eventually display in the dropdown on the Second Screen. Here, we 
 /// simply pull an existing List from the at_demo_data dependency.
 List<String> allAtSigns = at_demo_data.allAtsigns;
 /// We want to remove the [activeAtSign] from this List because we 
 /// can't chat with ourselves!
 allAtSigns.remove(activeAtSign);
 /// Again, call setState(() {}) to assign [allAtSigns] to the 
 /// variable [atSigns] that will be used in the dropdown widget.
 setState(() {
   atSigns = allAtSigns;
 });
 /// This is the only at_chat_flutter related function! 
 /// initializeChatService takes in an AtClientImpl instance, the 
 /// currently onboarded @sign, and the root domain for this project. 
 /// As its name suggest, this function will prepare the chat service 
 /// for us.
 initializeChatService(
     clientSdkService.atClientServiceInstance.atClient, activeAtSign,
     rootDomain: MixedConstants.ROOT_DOMAIN);
}


Because getAtSignandInitializeChat() is an initialization function, it is best to call it in the initState() function at the top of the _SecondScreenState class. The only other thing we need to do before calling the Chatting widget is deciding who wed like to chat with.

setAtsignToChatWith() {
 /// This function is as simple as calling the setChatWithAtSign() 
 /// function from the at_chat_flutter dependency with 
 /// [chatWithAtSign] passed in! [chatWithAtSign] is simply the @sign 
 /// that a user selects from the dropdown on the screen.
 setChatWithAtSign(chatWithAtSign);
}

We won’t want to call setAtsignToChatWith() in initState() because the function won’t know which @sign we’re communicating with until the individual selects it from the dropdown widget. Instead, it makes the most sense to place this function in the button (FlatButton for the at_chats app) that determines the navigation to the next screen. For at_chats, clicking the “Chat options” FlatButton will check to make sure that the “chatWithAtSign” variable is populated before it calls setAtsignToChatWith() and switches the “showOptions” variable to true, which allows the individual to see the two options for viewing the chatbox.

Now, for the moment of truth: once we’ve initialized the chat service, how do we create the actual chat screen? In most tutorials, you’ll probably be guided through a UI-heavy demo of different chatbox components and pairing a backend service. With the @platform, however, it’s really just one line of code:

(This snippet is directly from third_screen.dart in the at_chats project!)

class _ThirdScreenState extends State<ThirdScreen> {
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(title: Text('Chat')),
     /// You can simply set the body parameter of Scaffold widget
     /// to the ChatScreen widget from the at_chat_flutter dependency!
     body: ChatScreen(
       /// Optional parameters to customize your ChatScreen widget.
       /// You can find the full list of parameters in our Github 
       /// under the at_widgets repository.
       height: MediaQuery.of(context).size.height,
       incomingMessageColor: Colors.blue[100],
       outgoingMessageColor: Colors.green[100],
       isScreen: true,
     ),
   );
 }
}

By initializing the chat service and calling the ChatScreen() widget, you can make a fully-functioning one-to-one messaging application! While the ChatScreen widget offers a number of ways to customize your chatbox, if you’d like to build your own widget from scratch, you can use the at_chat_flutter dependency as a basis for creating your personal chat library that works with the @platform.

The Contacts Widget

Too many @signs to keep track of? That’s no problem with the at_contacts_flutter widget! Simply add the at_contacts_flutter dependency to your project, and you’ll be capable of performing several actions with your @sign contacts.

Learn more about the contacts widget here!

Use this package as a library

at_contacts_flutter: ^1.0.0

In order to implement the at_contacts_flutter widget, you must first, of course, create an AtClientService instance and authenticate an @sign.

After you have successfully onboarded an @sign, you can add a page where you may choose to show your contacts or show your blocked contacts. On load of this page, you will want to initialize the contacts service, similar to initializing the at_chats service. The contacts service needs to be initialised with the atClient from the AtClientService, current @sign, and the root domain.

initializeContactsService(
clientSdkService.atClientServiceInstance.atClient,
activeAtSign,
rootDomain: MixedConstants.ROOT_DOMAIN);

After successfully initializing the contact service, you will now be capable of getting the list of contacts that exist for the authenticated @sign. This is as easy as simply passing the contacts into a variable.

var _result = await _contactService.fetchContacts();

This fetchContacts() function exists in the _contactService file, which can be found within the at_contact’s ‘services’ folder. If you want to do more than just get the list of contacts, you have the capability of adding more contacts to this list, in addition to removing or blocking any. In order to retrieve the list of blocked contacts, it is similar to retrieving the regular list of contacts. The code from the example app demonstrates this well.

Class BlockedScreen extends StatefulWidget{
  @override
  _BlockedScreenState createState() => _BlockedScreenState();
}

class _BlockedScreenState extends State<BlockedScreen> {
  // Here, we are initializing a ContactService object in order
  // to call our list of blocked contacts later within our widget.
  // Refer to how the list is populated within the example app
  ContactService _contactService;
  @override 
  void initState() {
    _contactService = ContactService();
    _contactService.fetchBlockContactList();
    super.initState();
}

To block a contact, it is as easy as calling the blockUnblock method. If a contact is blocked, it will unblock the contact. If the contact is not blocked, it will block it for you.

await _contactService.blockUnblockContact(contact: _atSign_you_wish_toBlockUnblock);

After you block a contact, you may wish to have that contact removed from the list. All you have to do is simply implement the code below:

await _contactService.deleteAtSign(atSign: _atSign_you_wish_toRemove);

Along with the previously stated functionalities, the at_contacts_flutter package also provides the UI so there’s no need to set up a separate page to house these functions!

The Location Widget

One of the more common mobile application features is geolocation. Even if your app doesn’t explicitly use a map, with an individual’s permission, you can use their location for a variety of relevant recommendations like shops, restaurants, and nearby events. The at_location_flutter dependency is a powerful abstraction for geolocation with the @platform, and we’ll see some use cases of its most common functions.

Learn more about the contacts widget here!

Use this package as a library

at_location_flutter: ^1.0.3

Once we’ve successfully onboarded an @sign, let’s initialize our location service. For this subsection, we’ll base our code off of the example app in the Github directory for at_location_flutter.

initService() {
 /// A different way to call the currently onboarded @sign. In 
 /// practice, it is better to write a getAtSign() method in your 
 /// project's service file. This variable is used to display the 
 /// onboarded @sign at the top of the screen.
 activeAtSign =
     clientSdkService.atClientServiceInstance.atClient.currentAtSign;
 /// initializeLocationService() is a function from 
 /// at_location_flutter that's located in init_location_service.dart. 
 /// This function takes  in an AtClientImpl instance, the currently
 /// onboarded @sign, a GlobalKey to access the NavigatorState (for 
 /// navigating between routes), and the domain we want to point our 
 /// project to.
 initializeLocationService(
     clientSdkService.atClientServiceInstance.atClient,
     activeAtSign,
     NavService.navKey,
     rootDomain: MixedConstants.ROOT_DOMAIN
 );
}

As is the case with most @platform widgets, you can call this initialization function in the initState() function of your class.

Once our location service is ready to go, you can let the authenticated individual freely send and request locations to/from other @sign customers. These capabilities are made possible with the “sendShareLocationNotification” and “send RequestLocationNotification” functions (which exist in the init_location_service.dart file).

ElevatedButton(
 onPressed: () async {
   /// checkAtsign() is a helper functions that ensures the entered 
   /// @sign (for sending/requesting a location) is valid. It is
   /// unique to the example app in the at_location_flutter Github
   /// directory.
   bool result = await checkAtsign();
   if (!result) {
     CustomToast().show('@sign not valid', context);
     return;
   }
   /// This function takes in the @sign receiving the location
   /// notification as well as the duration (in minutes) of
   /// how long this shared location persists on the receiving
   /// @sign's secondary server.
   await sendShareLocationNotification(receiver, 30);
 },
 child: Text('Send Location'),
),
ElevatedButton(
 onPressed: () async {
   bool result = await checkAtsign();
   if (!result) {
     CustomToast().show('@sign not valid', context);
     return;
   }
   /// Similar to the previous function,
   /// "sendRequestLocationNotification" needs the @sign to
   /// request a location from.
   await sendRequestLocationNotification(receiver);
 },
 child: Text('Request Location'),
),

While the above two functions are certainly useful, there is another widget in the at_location_flutter dependency that offers a more elegant UI for sending your location, requesting locations, and even visualizing your current position. That widget is called “HomeScreen”.

/// When an individual clicks on the ElevatedButton that says “Show 
/// map”, the Navigator will lead them to the HomeScreen().
ElevatedButton(
 onPressed: () {
   Navigator.of(context).push(MaterialPageRoute(
     builder: (BuildContext context) => HomeScreen(),
   ));
 },
 child: Text('Show map'),
),

The HomeScreen displays a map with your location and offers two options (contained in “Task” widgets) that provide more user-friendly versions of the “sendShareLocationNotification” and “send RequestLocationNotification” functions (if you’re curious, these more elegant widgets are called ShareLocationSheet() and RequestLocationSheet() respectively). When you click on one of these tasks, a popup will appear to enter a receiving @sign (and duration for sharing a location), and any task you complete will appear in the bottom white region of the screen with its current status.

That’s all for the “Location” widget! If you want to test the at_location_flutter dependency for yourself, feel free to start by cloning the example app from the at_location_flutter Github repository. For more intricate functions like the location notification stream, our Github would be an excellent place to learn more.

The Events Widget

Like how we regularly share calendar items between our friends, family, and colleagues, it would be very convenient to have a data structure for events that works with the @platform. This is where the at_events_flutter dependency comes into play.

Learn more about the events widget here!

Use this package as a library

at_events_flutter: ^1.0.0

The first step, as you very well may have guessed, is the initialization of the event service. Like the previous few widgets discussed above, we’ll be examining snippets from the example app in the at_event_flutter Github directory throughout this subsection.

initService() {
 activeAtSign =
     clientSdkService.atClientServiceInstance.atClient.currentAtSign;
 /// Unlike most of the initialization functions, our event 
 /// initializer only needs an AtClientImpl instance and an optional 
 /// argument for the root domain.
initialiseEventService(clientSdkService.atClientServiceInstance.atClient,
     rootDomain: MixedConstants.ROOT_DOMAIN);
}

The most important function in the at_event_flutter library is CreateEvent(), which builds an instance of a CreateEvent that can be customized and shared across different @signs:

TextButton(
 onPressed: () {
   /// bottomSheet will return a pop up screen that takes up 90%
   /// of the screen height. 
   bottomSheet(
       CreateEvent(), MediaQuery.of(context).size.height * 0.9);
 },
 child: Container(
   height: 40,
   child:
       Text('Create event', style: TextStyle(color: Colors.black)),
 ),

CreateEvent() is a separate screen in the application that guides an individual through a list of fields they can populate to provide information about their event. If you look into the CreateEvent class, you’ll see that these fields are stored in an object called “eventData”, which is an instance of an EventNotificationModel. It’s full list of attributes is below (the ones with comments are used in the CreateEvent class):

class EventNotificationModel {
 EventNotificationModel();
 String atsignCreator;
 bool isCancelled;
 /// The title of the event.
 String title;
 /// A location serving as the event's venue.
 Venue venue;
 /// An object that stores info like event date, start time, and repeat duration.
 Event event;
 String key;
 AtGroup group;
 bool isSharing;
 bool isUpdate; //when an event data is being updated , this should be true.
 ...
}

“eventData” is a crucial data structure that’s used not just in creating an event but updating and deleting events as well. The init_events_service.dart file illustrates a variety of functions that can be used to perform useful actions on these objects.

One important feature of the example app is its EventList class, which doesn’t come directly with the at_events_flutter dependency:

TextButton(
 onPressed: () {
   Navigator.push(
     context,
     MaterialPageRoute(
       builder: (context) => EventList(),
     ),
   );
 },

This seemingly harmless class is actually doing quite a bit of work behind the scenes! EventList listens to an event stream that comes from an EventService object (a class within the at_event_flutter dependency) and displays them in a ListView format. Clicking on one of these events, you’ll be navigated to a popup of a CreateEvent instance with its “isUpdate” parameter set to true. This allows you to edit and save any event of your choice!

The Backup Keys Widget

When someone uses their @sign for the first time with an @platform app, it is important to have them authenticate with their generated QR code and create a set of backup keys just in case the ones in the keychain manager are lost or if you want to use the same @sign on a different device. The backup keys widget occurs during the “Onboarding” widget.

Learn more about the events widget here!

Use this package as a library

at_onboarding_flutter: ^1.0.0+4

You may notice that in order to get the at_backupKeys_flutter package, you can simply pull from the at_onboarding_flutter widget which houses the at_backupkeys_flutter widget! See below the process of at_onboarding_flutter to see where at_backupkeys_flutter comes into play!

at_cookbook
at_cookbook
at_cookbook

After inputting what @sign you wish to pair, you will need to upload the QR code retrieved from atsign.com. The emulator in the picture is not hooked up to a camera, so a small GIF of a house is there to fill where the camera would be. After successfully uploading and authenticating with the QR code, the backup key widget will be introduced to you! From the save option, you will be prompted to either save your keys to the files folder of the device or upload the keys to an associated Google Drive.

Fortunately, implementing the backup key widget is painless as it is a part of the onboarding widget! If you have already implemented the onboarding widget, there’s no code you need to write!

at_onboarding_flutter

A flutter plugin project for onboarding any @sign in @protocol apps with ease. Provides QRscanner and upload key file option to authenticate.

Learn more

at_chat_flutter

A flutter plugin project to provide chat feature using atsigns and atprotocol.

Learn more

at_common_flutter

A flutter package to provide common widgets used by other atsign flutter packages.

Learn more

at_backupkey_flutter

A flutter plugin project for saving backup key of any @sign that is being onboarded with @protocol apps. Backup key can used to authenticate in any @protocol apps.

Learn more

at_contacts_flutter

A flutter plugin project to provide ease of managing contacts for an atsign using atprotocol.

Learn more

at_contacts_group_flutter

A flutter plugin project to provide the group functionality with contacts using atprotocol.

Learn more

at_location_flutter

A flutter plugin project to share location between two atsigns and track them on OSM (open street maps).

Learn more

at_events_flutter

A flutter plugin project to manage events using the atprotocol.

Learn more

3.4 - The @protocol verbs

Understand the @platform verbs and their functions

from

The “from” verb is used to tell the secondary server what @sign you claim to be, and the secondary server will respond with a challenge. The challenge will be in the form of a full @ address and a cookie to place at that address. Before giving the challenge it will verify the client SSL certificate. The client SSL certificate has to match the FQDN list in the root server for that @sign in either the CN or SAN fields in the certificate. Learn More

cram

The cram verb is used to authenticate the @sign to the secondary server. On successful request, binds the @sign to the secondary server. The secret is appended to the challenge (response of from verb) and gives a SHA512 digest which serves as an input to the CRAM verb. On successful cram verb request, the @sign is successfully authenticated to the secondary server and allows user to Add/Update, Delete and lookup the keys in their respective secondary servers. We use “cram” authentication for the first time and will create a public/private key pair for pkam authentication for subsequent logins. Learn more

pkam

The pkam( Public Key Authentication Mechanism) verb is used to authenticate the @sign to the secondary server. This is similar to how ssh authentication works. On successful request, binds the @sign to the secondary server.On successful pkam verb request, the @sign is successfully authenticated to the secondary server and allows user to Add/Update, Delete and lookup the keys in their respective secondary servers. Learn more

scan

The “scan” verb scans the available keys. The scan verb when used by unauthenticated @sign user, scans for keys that are publicly available to you.The scan when used by an authenticated user via the cram verb, scans all the available keys on the secondary server. You can use scan verb with regex if you want to get keys matches with the regex. Learn more

lookup

The “lookup” verb allows the lookup of a particular address in the @ handles namespace. The “lookup” verb provides public lookups and specific key look ups when authenticated as a particular @ handle using the “from” and “pol” verbs. If a lookup is valid the resulting information is returned with the data: header and a carriage return and a further @ prompt ready for further commands. If the lookup is not valid then a null is returned again with the data: header. The @sign should be authenticated using the cram verb prior to use the lookup verb. Learn more

plookup

The “plookup” verb, provides a proxied public lookups for a resolver that perhaps is behind a firewall. This will allow a resolver to contact a @ server and have the @ server lookup both public @ handles information. This will be useful in large enterprise environments where they would want all lookups going through a single secondary server for the entity or where a single port needs to be opened through a firewall to lookup @ handles. The @sign should be authenticated using cram verb prior to use the plookup verb. Learn more

llookup

The “llookup” verb can be used to locally lookup keys stored on our secondary server. To perform local look up, the user should be successfully authenticated via the “cram” verb. Learn more

update

The “update” verb is used to create/update the keys in the secondary server. We can create/update both public and private keys. kThe update verb is used to set public responses and specific responses for a particular authenticated users after using the pol verb. The @sign should be authenticated using cram verb prior to use the update verb. Learn more

delete

The “update” verb is used to delete the keys in the secondary server. A delete request must contain the distinguished name of the key to be deleted. The @sign should be authenticated using the cram/pkam verb prior to use the delete verb. Learn more

notify

The “notify” verb used to notify a key to another atsign. The @sign should be authenticated using the cram/pkam verb prior to use the notify verb. You can send a notification to multiple users using “notify:all” command. Also you can list out all the notifications using “notify:list”. Learn more

monitor

The “monitor:” verb is used to monitor either all or specific notification events that are sent using the “notify:” verb. Notifications are both queued and managed by the secondary server, and the status of an individual notification can also be seen. Learn more

stats

The “stats” verb used to get all the available metrics. We can get specific metrics by providing ‘,’ separated list like stats:1,2. If we didn’t provide anything it will return all the metrics information. Learn more

sync

The “sync” verb is used to fetch all the changes after a given commit sequence number from the commit log on the server. This verb is helpful when local and remote secondary servers are not in sync. We can sync only specific keys by providing regex pattern Learn more

config

The “config” verb is used for configuring or viewing an @sign’s block/allow list. ‘from’ verb functionality is dertermined by using the configurations of ‘config’ verb. If an atsign is in block list, secondary server won’t allow it for authentication. Learn more

pol

The “pol” verb allows to switch as another @sign user. To switch as another user, use from:<@sign>(The another @sign user) verb which gives a response as proof:; then use pol verb. On successful authentication, the prompt changes to the another @sign user. If we authenticate to other atsign using pol, we can only access public information available. Learn more

4 - Sample apps created on the @platform

Sample @platform apps, from simple to complex

at_hello_world:

Demonstrates some of the most common verbs and methods that can be found on the @platform. If you are new to the @platform, start here!

Learn more

at_chats:

Demonstrates peer-to-peer chatting capabilities and just how easy it is to implement into any project!

Learn more

at_cookbook:

Demonstrates some of the more complex verbs and methods that the @platform has to offer. Similar to at_chats in the sense of sending information to separate @signs. At_cookbook builds upon this allowing you to send objects such as recipes to separate @signs!

Learn more

@mosphere:

Currently our most complex application on the @platform! This app sends entire files from one @sign to another with end-to-end encryption! We highly recommend having a strong understanding of all of the common verbs and methods of the @platform before dissecting @mosphere!

Learn more

4.1 - at_hello_world

Not sure where to start? Take a look at our at_hello_world app to see how some of the common verbs and methods of the @protocol are applied and implemented.

If you have gone through the steps of setting up the virtual environment and wish to learn how to implement a few common verbs and methods of the @platform, we highly recommend walking through the at_hello_world application.

Below, you can see a small demonstration of how the at_hello_world application works.

at_hello_world

tl;dr

Overview too long for you? Watch the Tyler Time episode that covers this instead!

Overview of the at_hello_world app

“at_hello_world” is a bit of a misnomer. Beyond the fact that this app does a lot more than printing “Hello World!” on the console of your IDE, if you lift its hood, you’ll find a tremendous amount of stuff going on (tracing all the functions called in the server_demo_service.dart file will get you several abstraction layers deep into the @protocol!). By no means do you have to understand everything that is happening behind the scenes in the at_hello_world application, but it’ll definitely help to grasp the basics.

Just like the rest of the @platform, all of our demo applications are open source. Feel free to download the at_hello_world code from our GitHub repository here.

Upon downloading and booting up the app on an emulator, you are met with the Login screen where you can login after selecting a testable @sign to authenticate with from the dropdown menu.

After successfully authenticating, you will be taken to the home screen where you will see three separate boxes which house the three main functons of the at_hello_world app.

The Three Main Functions of the at_hello_world app

Update

The update section, as you see within the code, actually only involves a single if statement (to ensure information is actually passed) and four lines of code within it.

  _update() async {
    if (_key != null && _value != null) {
      AtKey pair = AtKey();
      pair.key = _key;
      pair.sharedWith = atSign;
      await _serverDemoService.put(pair, _value);
    }
  }

Above is the entirety of the update function! The “pair” variable in the first line of the if statement is something that you will see in all @platform applications. The @protocol interprets keys as AtKey objects, which have several attributes like “key”, “metadata”, and “sharedBy” that help the backend understand what to do with them.

In the code snippet above, we are calling the “key” attribute to add a string that will be paired to a value and the “sharedWith” attribute to define with whom we are sharing this AtKey-value pair. If we’d like to store “hello” and “world” on @bob’s secondary server, we would set pair.key to “hello” and pair.sharedWith to “@bob”. This latter detail may be a bit odd: Bob is sharing this AtKey object with himself so that he can access it! You can see use cases of sharing AtKey-value pairs with other @signs in the at_cookbook sample app.

Following up with our “hello” and “world” example, the final step in the _update function is to call the “put” verb from the _serverDemoService object with “pair” as the AtKey instance and “world” as the corresponding value (which should just be a string). When the verb executes successfully, you will have put the “hello” and “world” key-value pair into @bob’s secondary server!

While this is certainly an impressive feat (after all, these few seemingly unassuming lines of code uniquely encrypts the key-value pair to @bob’s secondary server and makes it persist), we’re still limited by the fact that we can’t retrieve key-value pairs from a secondary server. In the @protocol, retrieving key-value pairs takes two steps: scanning the relevant secondary server for AtKey objects, and getting the value associated with a scanned AtKey object.

Scan

Now that we’ve “put” information on our secondary, we’d like to retrieve that key in order to read the information associated with it. In order to display values that we’ve stored, we first need to scan a secondary server for relevant AtKey objects (i.e. those that belong to the “namespace” of the application) and retrieve the values corresponding to those AtKeys.

_scan() async {
    List<AtKey> response = await _serverDemoService.getAtKeys(
      sharedBy: atSign,
    );
    if (response.length > 0) {
      List<String> scanList = response.map((atKey) => atKey.key).toList();
      setState(() => _scanItems = scanList);
    }
  }

The only @protocol verb we’re calling in this snippet is “getAtKeys()”. This verb is an incredibly robust function that can gather and sort AtKeys on a secondary server based on things like who shared those AtKeys (the “sharedBy” optional argument) and regular expressions (e.g. the namespace of the application). Because the at_hello_world app is a special case where we only share AtKey objects with ourselves, we can simply call getAtKeys with the “sharedBy” argument set to our own @sign (i.e. widget.atSign). This will return a List of the AtKey objects we want.

Once you get that List of AtKeys, you’re pretty much finished! In the at_hello_world app, because we want to display keys as strings, we call the “map” method on the List of AtKeys to create a new list that just contains the “key” attribute of each AtKey object. In the last line of code, we call “setState” so that the app loads the newly populated list of keys in the DropdownButton widget.

Lookup

An individual on the at_hello_world app is given a list of keys, and they select one (_lookupKey) to find its corresponding value. How do we do this? The answer lies in the _lookup function of the HomeScreen class:

 _lookup() async {
    if (_lookupKey != null) {
      AtKey lookup = AtKey();
      lookup.key = _lookupKey;
      lookup.sharedWith = atSign;
      String response = await _serverDemoService.get(lookup);
      if (response != null) {
        setState(() => _lookupValue = response);
      }
    }
  }

In the first line of the if statement, we are creating a new AtKey object called “lookup.” The reason for this is we need a dummy AtKey object that can be passed into the @protocol for looking up the correct value. For the at_hello_world app, this dummy AtKey just needs its “key” and “sharedWith” attributes populated before it can be passed into the “get” verb.

By the way, if you think creating a copy of an AtKey object is a hassle, that’s totally valid! In a typical @platform application, you have the _scan and _lookup functions merged to some degree so that you can just pass in the AtKey objects we retrieved with the “getAtKeys” verb to the “get” verb. The point of having two separate functions in the at_hello_world project is to define the “scanning” and “getting” steps more concretely.

“Get” is a very straightforward verb: it gets the value corresponding to a specified AtKey.

Once we retrieve the value paired with the “lookup” AtKey, all that’s left is calling “setState” to display the “_lookupValue” on screen.

4.2 - at_chats

Demonstrates the peer to peer chatting capabilities and just how easy it is to implement into any project!

The at_chat_flutter widget offers a messaging experience that is unique to the @platform. In a traditional messaging application, your texts are stored in a remote database and the person you’re pinging pulls the texts from there (a bit unsettling if you think about it). Of course, there is no such thing as a remote database in the @platform, so we had to be a bit clever coming up with a messaging scheme. In a nutshell, your text messages are not “sent” but rather “shared” with another @sign. All your texts are stored securely in your secondary server and never leave; if you decide to send a message to someone, that person is given permission to view that text via the notify verb. You can see use cases of the notify verb in the at_cookbook sample app.

Below, you can see a small demonstration of how the at_chats application works.

at_chats

tl;dr

Overview too long for you? Watch the Tyler Time episode that covers this instead!

Overview of the at_chats app

Although this messaging dynamic might sound a bit involved, set up is quite easy! To get a feel for using the “Chatting” widget, it’s best to follow along with the at_chats demo application.

The general flow of all @platform widgets is onboarding an @sign => initializing the service object => creating the actual widgets. Assuming we’ve already onboarded an @sign, let’s look at the steps to initialize our chat service:

(The following code snippets are taken directly from at_chats. While there will be explanations, don’t worry too much about all the variables!)

getAtSignAndInitializeChat() async {
 /// In the at_chats app, the onboarded @sign is displayed at the top
 /// of the Second Screen. We set that @sign to [currentAtSign].
 String currentAtSign = await clientSdkService.getAtSign();
 /// Set [activeAtSign], which is the variable that gets displayed, to
 /// [currentAtSign] using setState(() {}).
 setState(() {
   activeAtSign = currentAtSign;
 });
 /// Initialize a List of Strings called [allAtSigns] that we will
 /// eventually display in the dropdown on the Second Screen. Here, we
 /// simply pull an existing List from the at_demo_data dependency.
 List<String> allAtSigns = at_demo_data.allAtsigns;
 /// We want to remove the [activeAtSign] from this List because we
 /// can't chat with ourselves!
 allAtSigns.remove(activeAtSign);
 /// Again, call setState(() {}) to assign [allAtSigns] to the
 /// variable [atSigns] that will be used in the dropdown widget.
 setState(() {
   atSigns = allAtSigns;
 });
 /// This is the only at_chat_flutter related function!
 /// initializeChatService takes in an AtClientImpl instance, the
 /// currently onboarded @sign, and the root domain for this project.
 /// As its name suggest, this function will prepare the chat service
 /// for us.
 initializeChatService(
     clientSdkService.atClientServiceInstance.atClient, activeAtSign,
     rootDomain: MixedConstants.ROOT_DOMAIN);
}

Because getAtSignandInitializeChat() is an initialization function, it is best to call it in the initState() function at the top of the _SecondScreenState class. The only other thing we need to do before calling the “Chatting” widget is deciding who we’d like to chat with.

setAtsignToChatWith() {
 /// This function is as simple as calling the setChatWithAtSign()
 /// function from the at_chat_flutter dependency with
 /// [chatWithAtSign] passed in! [chatWithAtSign] is simply the @sign
 /// that a user selects from the dropdown on the screen.
 setChatWithAtSign(chatWithAtSign);
}

We won’t want to call setAtsignToChatWith() in initState() because the function won’t know which @sign we’re communicating with until the individual selects it from the dropdown widget. Instead, it makes the most sense to place this function in the button (FlatButton for the at_chats app) that determines the navigation to the next screen. For at_chats, clicking the “Chat options” FlatButton will check to make sure that the “chatWithAtSign” variable is populated before it calls setAtsignToChatWith() and switches the “showOptions” variable to true, which allows the individual to see the two options for viewing the chatbox.

Now, for the moment of truth: once we’ve initialized the chat service, how do we create the actual chat screen? In most tutorials, you’ll probably be guided through a UI-heavy demo of different chatbox components and pairing a backend service. With the @platform, however, it’s really just one line of code:

(This snippet is directly from third_screen.dart in the at_chats project!)

class _ThirdScreenState extends State<ThirdScreen> {
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(title: Text('Chat')),
     /// You can simply set the body parameter of Scaffold widget
     /// to the ChatScreen widget from the at_chat_flutter dependency!
     body: ChatScreen(
       /// Optional parameters to customize your ChatScreen widget.
       /// You can find the full list of parameters in our Github
       /// under the at_widgets repository.
       height: MediaQuery.of(context).size.height,
       incomingMessageColor: Colors.blue[100],
       outgoingMessageColor: Colors.green[100],
       isScreen: true,
     ),
   );
 }
}

By initializing the chat service and calling the ChatScreen() widget, you can make a fully-functioning one-to-one messaging application! While the ChatScreen widget offers a number of ways to customize your chatbox, if you’d like to build your own widget from scratch, you can use the at_chat_flutter dependency as a basis for creating your personal chat library that works with the @platform.

4.3 - at_cookbook

This is an intermediate-level @platform based application that uses the verbs we learned in the at_hello_world and at_chats applications to make a working cookbook for the chef inside of us all!

at_cookbook

tl;dr

Overview too long for you? Watch the Tyler Time episode that covers this instead!

Overview of the at_cookbook app

The at_cookbook app allows a testable @sign to create a recipe with a name, description, list of ingredients, and a picture. After doing this, the @sign is capable of sharing this entire recipe with another testable @sign. A dishWidget class is created which encapsulates an individual recipe with each instance. Its parameters are defined below:

class DishWidget extends StatelessWiatdget {
 final String title;
 final String ingredients;
 final String description;
 final String imageURL;
 final String prevScreen;

 DishWidget({
   @required this.title,
   @required this.ingredients,
   @required this.description,
   @required this.imageURL,
   @required this.prevScreen,
});
...

After we pull dishWidgets that exist in a secondary server, we display them on the home screen, where the list of recipes are located.

Now that you have the recipe itself, you’re able to pass this through the notify verb. When an @sign wishes to share a recipe, the _share function will be called. This function is structured as so:

_share(BuildContext context, String sharedWith) async {
 if (sharedWith != null) {
   AtKey lookup = AtKey()
     ..key = widget.dishWidget.title
     ..sharedWith = atSign;

   String value = await _serverDemoService.get(lookup);

   var metadata = Metadata()..ttr = -1;
   AtKey atKey = AtKey()
     ..key = widget.dishWidget.title
     ..metadata = metadata
     ..sharedBy = atSign
     ..sharedWith = _otherAtSign;

   var operation = OperationEnum.update;
   await _serverDemoService.notify(atKey, value, operation);
   Navigator.pop(context);
 }
}

Here, we’re initializing a variable called lookup as an AtKey object (lookup will be our recipe). You’ll notice that we’re defining a couple of the attributes of the AtKey object (mainly the name of the recipe and what @sign is this recipe being shared with).

We would like to “get” the values of our recipe, so we use the get verb from the serverDemoService file of the application. ttr (Time To Refresh), a metadata attribute, is called with a value of -1, which means that we’re confident that the values of our recipe won’t change. Once the recipe has been cached on the secondary server that has received the recipe, it will not need to worry about updating its values at any point.

After passing all of the necessary values such as the metadata, the appropriate @signs, and the type of notification we’d like to send, we simply pass the values through the notify verb!

4.4 - @mosphere

Makes peer-to-peer encrypted file sharing possible.

In real-time, you can send files across any device regardless of your location — with the added benefit of total privacy. You can fearlessly share contracts, tax information, or other confidential information without worrying about your data being stored on a server in the cloud.

To see a demonstration of @mosphere, refer to the GIF below:

atmosphere-walkthrough

Creating your own @platform data-streaming application

Just like any Flutter app, an @platform application requires a little bit of setup before you can get started. Here are those steps:

  1. Add the service file to your app: You can simply copy this service file from our demo at_hello_world application. These files contain helper methods that allow you to implement @protocol functionality with just a couple lines of code.
  2. Add the configuration file to your app: Again, feel free to copy this from the at_hello_world and @mosphere application. This file contains variables that allow you to use the virtual environment. Make sure that the ROOT_DOMAIN string is set to vip.ve.atsign.zone and you have a unique name for the NAMESPACE of your @pp!
  3. Copy the dependencies from the at_hello_world and @mosphere pubspec.yaml files and put them into your project.

We are super glad that you are beginning your journey as an @dev. We highly recommend that you join our discord dev community for troubleshooting, dev updates, and much more!

5 - The @platform FAQs

FAQs and issues reported for the @platform

Frequently Asked Questions

5.1 - The @platform FAQs

Have a question revolving around the @platform? Here you will find those answers!

Our Mission

Now’s your chance to bring your app idea to life. Our free, open source platform makes it easy to create end-to-end encrypted apps that are surveillance-free and private by design — no backend infrastructure required. Our entire community is here to help you build, launch and monetize an amazing app experience for your customers.

Why should I trust you (The @ Company) and your systems?

Trust certainly has to be earned, so we have started with an open protocol specification and an open source reference implementation for the full stack platform that everyone can evaluate and contribute to. As a company, the only thing we are uniquely responsible for is the integrity of the namespace, which does not hold any private information.

The only thing that we have centralized is the verified location of where to go to request permission for access to information from someone. Our basis for trust in our company and the systems and services we provide relies on the fact that we do not have access by any means to anyone’s private data.

What makes the @platform secure?

We do not want to be the Google of identity. We want each person to be able to own and control access to their own data. The first principle for us is:

“It is provably true that The @ Company cannot access your private information without your explicit permission.”

The owners of @signs hold the keys for both access and encryption, and nobody else—including The @ Company—has access to them. Thus, only two entities in the universe — the entity that shares information and the entity that receives it — can access private information that is shared between them.

What’s to prevent a malicious app from misusing the data produced through my app?

Our strategy for preventing a malicious app from screwing with data at the moment is to review and certify applications to eliminate such behavior. We also have an ambition to automate the process as much as we can. We are currently evaluating how to control app level access (read and write) to data using a namespace convention, which is already a part of the @protocol spec and reference implementation.

Who would you regard as your main competitors and how are you different?

Notionally the blockchain cohort making similar claims would be the main ones, but we believe that they are more likely to become adopters over time to provide non-repudiation and to eliminate username/password authentication which has proven to be so risky. Technically, Solid/Inrupt is somewhat similar with their data pods, but they curiously have no built-in encryption at all and are enterprise focused where we are developer/apps/consumer focused.

5.2 - Flutter FAQs

FAQs and issues reported for the @platform

Flutter Issues

Encountered Development Errors

  • The following two links are a temporary solution to easily finding/submitting error solutions, if you have any suggestions, we are happy to hear them!
  • If you have a bug/issue, feel free to search for it in this spreadsheet.
  • If the issue you are currently encountering does not exist within the spreadsheet linked above, feel free to submit a new error within this error submission form.

Flutter doctor says that Android Studio is not installed but it is

Android Studio (not installed) , when run flutter doctor while Android Studio installed on machine - Stack Overflow

Flutter doctor says that java needs to be installed

Install Java - Java SE Development Kit 16 - Downloads (oracle.com)

Flutter Doctor says you have to agree to licenses

But when you run ‘flutter doctor –android-licenses’ you get a load of errors that is fixed with - windows - Flutter Doctor –android-licenses : Exception in thread “main”

6 - @platform Additional Resources

All the resources you will need for developing on the @platform

6.1 - Step-by-step dess guides

Learn how to setup dess on a specific platform

6.1.1 - Setup dess on AWS (Amazon Web Services) Platform

Step-by-Step setup of dess on AWS (Amazon Web Services)

Step-by-Step setup of dess in AWS

In this step-by-step guide I will walk you through all steps required to setup your own private dess using AWS. Please use the index to skip some steps in case you have already completed them.

Table of contents

Pre-requisites

  • Registered @sign(s) to setup
  • An AWS account
  • A Fully Qualified Domain Name (FQDN)

1. Registering your @sign

This topic is already well documented. Please follow the guidance of Our FAQs and register via the registrar site.

2. Sign-up for AWS account

If you are new to AWS, signing up for an account is free! The cost of running dess is about 10$/month. You can create your account at https://aws.amazon.com/ and as of June 6th, 2021 there is a “free tier” available which was used during the making of this guide.

aws-free-trial

Follow the instructions on screen.

aws-sign-up

Once you are done with registration, you will be able to login to your aws console.

Make sure that you select the correct region in the top right corner.

aws-region

Select the region that is geographically closest to your location for best performance.

You are now setup on AWS and ready to prepare dess.

3. Register your own fully qualified domain name (FQDN)

This step can be performed at a variety of sites, all with different pricing models. You can use sites like Go Daddy, Namecheap, and many others. However, since we have AWS account, we can use it to register our domain through the Route 53 service.

In your AWS console navigate to services in top left corner and select Route 53.

a) Register domain name with AWS.

In your AWS console search for Route 53.

aws-route53

You can start looking for your domain directly from here:

image-20210726083635919

Based on the domain name you search, AWS will give you similar options, and their pricing. As I am looking for the best deal, the .link domain seems like a good option at a cost of 5$ / year.

In my case 4atsign.link is free and I will register it by clicking “Add to cart” and continue.

img

Fill out DNS registration form:

img

Continue review details and order. At this point if all is fine you should see your domain request pending:

img

This can take some time so why don’t we move on to next step!

4. Preparing AWS instance

Now since I am new to AWS, the easiest way to get started is by using the LightSail service from service catalog. This will enable you to deploy small system which is more then capable of handling dess at pre-set price.

img

Welcome to LightSail:

img

First step is to create new instance. Fortunately, we have big orange button that can do just that!

There are several options we are presented at this moment. Since I am living in Europe I select “Frankfurt, Zone A (eu-central-1a)” as my instance location. Instance region will dictate how well will your instance response based on your geographical location. People located in India should selects APAC region where as people in US should select North America region. You can leave availability zone set as default.

img

Next up will be selection of operating system we want to deploy. We know that dess works well with Ubuntu 20.04 LTS so lets select just that.

img

You are presented with couple more options, but unless you know what you are doing leave these as is.

img

Now let’s select instance plan. dess is relatively light weight so for testing purposes I will select first instance plan for 3.5$/Month. This will provide us with 512 MB of RAM, 1vCPU, 20GB of storage and 1TB of data transfer. This is more then enough to run our dess.

img

Lastly we have to name our instance. This is the name you will be presented with in your dashboard.

img

Last but not least is to press “Create instance”

img

After a couple of seconds you should be re-routed to your dashboard and see your instance up and running:

img

5. Preparing your instance for network access

a) Assignment of Static IP

Next up, is to provide our instance with a static IP and linking our domain to it.

When you click on your instance name, it will take you to the management console, which should look like this:

img

This is where you control hardware, connectivity and if needed can delete your instance.

Lets configure a static IP address for your new instance. Navigate to Networking and click on Create static IP:

img

Our region and instance is selected, so the only thing left is to name our static IP. I selected the name atsign-static, but it can be any name you like.

img

Lets hit create:

img

And voila, we now have a static IP address on the internet and it will not change. Now we can link our domain name with it.

img

When you click on your instance name and navigate to Networking, the static IP is now assigned.

img

b) Assignment of Domain name to your static IP

We can now move on to linking our static IP address to our domain. This is done via the AWS console which can be accessed in the top right of Lightsail.

img

Verify your email used for registering domain:

By now you should receive verification email that will confirm registration of your domain. Click this link before moving on.

Linking domain with your static address:

Lets navigate to “Route 53” from Services menu.

img

From your dashboard click on “Domain” which will take you to the “Registered Domains” tab.

img

Here you can click on your registered domain which will take you to overview page with domain status and contacts.

img

Click on “Manage DNS”

img

And click on your domain name.

This will show you your DNS records for your domain. We now need to link A type record to your domain linking it to IP address of your instance.

This is done simply by typing your static IP address from previous step into field “Value” and clicking Create record:

img

If everything goes well you should see following in your domain dashboard:

img

To test if you are successful open command line and ping your domain. You should see your instance static IP address. It will not respond which is normal due to IPv4 firewall. It is actually good thing!

img

At this point we have created DNS record we will use to link our dess, we created instance name which will be running our dess and we have opened port range which is exposed to the internet and we can communicate with @sign root server and our apps with.

c) Setting up Firewall

Next up we need to make sure we have ports open for our dess to communicate with root server and our apps. In Section networking go to section “IPv4 Firewall” and click “+ Add rule” Our rule will be “Custom” on TCP protocol with Port range in number higher then 1024. In my case I have selected port range 8000-8010. This will enable me to run up to 10 @signs in parallel.

img

Click create and verify that your new rule is in list:

img

6. Instance setup and dess deployment

Open your LightSail console

By now you should see your instance in “Running state”

img

Open it and on tab Connect click on “Connect using SSH”

img

You should be presented by a new window with command line:

img

Before we do anything else, we should update the system:

sudo apt update && sudo apt upgrade

This might take some time, but it will make sure we have latest repository information and the system is up to date.

Next make sure curl is installed, we will use curl to pull the dess installation file:

sudo apt install curl

Finally, run the dess installer:

curl -fsSL https://getdess.atsign.com | sudo bash

Once the installer is finished you should be prompted like so:

Dess installed, please move on to the sudo dess-create command.

7. Registration of @sign in your private dess

At this step you should already have your @sign registered at http://atsign.com. If not go do it!

I have registered my own free @sign (@44likelycanary) which I will link to my dess.

In your instance console, navigate to dess folder. If you were following this guide it will be located in:

We now need to create the service that will host our @sign by executing the dess-create command:

$ sudo dess-create @44likelycanary 4atsign.link 8000 <email address> likelycanary

To make it more understandable:

I will be registering my @sign @44likelycanary.

I will be using my domain 4atsign.link which I have registered through AWS.

I am using port 8000 which I have opened in my instance firewall.

My registration email address is <email address> (this email is used to sign the SSL certificates).

The last likelycanary is the name that docker will use to track the service.

If everything is successful you should see output like this:

img

At this moment your @sign is registered on your dess.

8. Activation of @sign

Next up we need to activate it

Login to your dashboard at https://my.atsign.com/dashboard

Open “my @signs”

img

Open “managed” of @sign you are registering”

img

Navigate to Advance settings:

img

If you have already activated your @sign you will be prompted to erase all your data first

img

Once done you are able to link your @sign with your private dess. Use your domain and port number with which you have created service on your cloude instance and press Activate.

img

You should see that your @sign is being activated in your dashboard:

img

This can take several minutes so go get cup of coffee, some tea maybe, stretch your body and pray you haven’t made any mistakes!

Once the activation process completes you are welcomed by green Activated.

img

You can now open @buzz or @wavi and register your @sign via QR code and generate your keys!

CONGRATULATIONS

6.1.2 - Setup dess on GCP (Google Cloud Platform)

Step-by-Step setup of dess on GCP (Google Cloud Platform)

dess stands for “Distributed Edge Secondary Server” and it is used to host your @signs on your own secondary server. Refer to the Setup dess guide under Options to learn more.

In this step-by-step guide we will walk you through all steps required to setup your own private dess in GCP cloud from scratch. Please use index to skip some steps in case you have done them in another way.

Table of contents

Pre-requisites

  • Register Atsign at http://atsign.com
  • Have google account
  • Have registered Fully Qualified Domain Name (FQDN)

1. Registering your @sign

This topic is already well documents. Please follow guidance of https://atsign.com/faqs/ and register via https://atsign.com/get-an-sign/.

2. Sign-up for GCP account

a) Account creation

If you are new to cloud like me and need to create new GCP account, I have good news! The creation is for free. As promotion all new customer will also receive 300$ as credit. That is more than enough to run multiple dess’s for 3 months of offer validity.

gcp-discount

You can register with your gmail account or create new one by clicking “Get started for free” and follow instructions to register

Get Started

Once done with registration you will be able to login to your https://console.cloud.google.com/ And voila you have your GCP account up and running.

b) Setting up billing

To be able to run some services you have to maintain billing account. Navigation Menu -> Billing

gcp-navigation-billing

By default GCP creates “My Billing Account” which you can link to your project.

gcp-billing_project

Click “Link Billing account” and select “My billing account” from drop down

🔴 Its important to note that this account holds your 300$ free credits! 🔴

We are all setup and ready to go deploy!

3. Register your own fully qualified domain name (FQDN)

This step can be performed at range of different sites with different pricing models. You can use sites like http://www.godaddy.com; https://www.namecheap.com/; and many others. Since we have GCP account we can use it to register our domain through Cloud Domain.

a) Register domain name with GCP.

In your GCP console search for Cloud Domain.

gcp-search-domain

We first need to enable this service.

gcp-domain-api

Once the service activates you will be presented with its dashboard.

Lets register our fully qualified domain name (FQDN) that will be used for registration of our dess.

Click on “Register Domain” and look for suitable name.

gcp-domain-register

Reviewing pricing options of GCP .pw is their cheapest option which will work for testing. For my test case I am selecting atsign.pw with price $0.75 / month by clicking add to cart button and continue.

gcp-domain-lookup

Next we can select where will our DNS record be hosted. Simply select “Use Google Domains” and DNSSEC “Enabled” and click continue.

gcp-domain-config

We have no options with Privacy protection so simply click continue.

gcp-domain-privacy

Fill out contact details and click register. This will trigger registration email you will have to verify.

gcp-domain-contacts

Once you verify your email your domain should be ready to use

gcp-domain-status

b) Create Cloud DNS zone

Next step is to enable Cloud DNS service. Search for DNS in search bar and select Cloud DNS

gcp-search-dns

If its your first time activating this service you will have to enable the API. Press enable and wait for the activation to finish.

gcp-dns-api

Lets crate new DNS zone by clicking “Create Zone”

gcp-dns-create

We will select zone type as Public since we will be connecting to our DNS from internet and provide your registered DNS name. In my case atsign.pw. DNSSEC will be set to off and provide some meaningful Description. Once you filled all your details press create.

gcp-dns-create-details

You should receive following message:

gcp-dns-confirm

4. Preparing GCP instance

Now since I am new to GCP the easiest way to start using it is with prebuild solutions. This way you will deploy small system which is more then capable of handling dess at pre-set price.

We can use pre-build “Ubuntu 20”. In Search bar look for Ubuntu20

gcp-search-ubuntu20

🔴 Make sure to use “Ubuntu 20” and not “Hardened Ubuntu 20”. Although the Hardened version will work as well it requires additional manual steps to make work.🔴

This will take you to this prebuild solution overview page:

gcp-ubuntu20

Select launch

gcp-ubuntu20-api-enable

And press enable all required API’s

gcp-ubuntu20-api-enabled

Once all API’s are activated you are taken to configuration page:

gcp-ubuntu20-type

Prices are based on region and power of selected Virtual Machine (VM). To cost optimize you can select US region / N1 / g1-small at cost of $15/Month.

Next up is boot disk which we can leave as is.

gcp-ubuntu20-disk

This will deploy your Ubuntu 20.04 virtual machine.

gcp-ubuntu20-confirmation

5. Preparing your instance for network access

a) Assignment of Static IP

Next up our list of activities is providing our instance with static IP and linking our domain to it.

GCP assigned ephemeral IP address to our newly created VM. We need to change it to static IP.

In search bar look for External IP addresses.

gcp-search-networking

You should see your external IP address assigned to your VM

gcp-networking-overview

In column Type select ephemeral and change it to Static

gcp-networking-type

Give your static IP name and some description.

gcp-networking-static

Type should now say Static

gcp-networking-type-change

b) Assignment of Domain name to your static IP

Next step is to point your domain to your virtual machine running dess.

Search for Cloud DNS

gcp-search-dns

Open zone you have created in step 3.b Create Cloud DNS zone

gcp-dns-status

We now need to link A type record to your domain linking it to IP address of your Virtual machine.

This is done simply press “Add record set”

gcp-dns-add-record

Select Resource record type “A” and IPv4 address the address of your dess virtual machine.

gcp-dns-a

If everything goes well you should see following in your domain dashboard:

gcp-dns-status-final

Next step is to update Google Name servers. You can follow Googles guide - step 5.

https://cloud.google.com/dns/docs/tutorials/create-domain-tutorial#register-domain

To test if you are successful open command line and ping your domain. You should see your instance static IP address.

gcp-dns-test

At this point we have created DNS record we will use to link our dess, we created instance name which will be running our dess and we have opened port range which is exposed to the internet and we can communicate with @sign root server and our apps with.

c) Setting up Firewall

Search for Firewall in search bar.

gcp-search-firewall

Click on Create firewall rule

gcp-firewall-create

Lets create firewall rule that will enable the @sign root server communicate with our dess.

gcp-networking-firewall-settings

Important things to note:

  1. Ingress translates to incoming traffic.

  2. Selecting IP range as 0.0.0.0/0 will allow traffic from anywhere on the internet.

  3. For my use case I will enable port range 8000 – 8010 allowing me to register up to 10 @signs.

gcp-firewall-ranges

Press create and validate that your new rule appears in list of firewall rules.

gcp-firewall-status

Second we need to create firewall rule that will enable your dess server to communicate with certification authority.

gcp-networking-firewall-80

Important things to note:

  1. Ingress translates to incoming traffic.

  2. Selecting IP range as 0.0.0.0/0 will allow traffic from anywhere on the internet.

  3. You need to enable port 80 for communication with Certification authority.

gcp-networking-firewall-range-80

Press create and validate that your new rule appears in list of firewall rules.

gcp-firewall-status

6. Instance setup and dess deployment

Open your GCP console at https://console.cloud.google.com/compute/instances and search for VM instances

gcp-search-vm

By now you should see your instance in “Running state”

gcp-vm-status

Click on the SSH button and connect to your instance.

You should be presented by new window with command line:

gcp-vm-connected

Before we do anything else, we should update the system:

sudo apt update && sudo apt upgrade

This might take some time, but it will make sure we have latest repository information and the system is up to date.

Next make sure curl is installed, we will use curl to pull the dess installation file:

sudo apt install curl

Finally, run the dess installer:

curl -fsSL https://getdess.atsign.com | sudo bash

Once the installer is finished you should be prompted like so:

Dess installed, please move on to the sudo dess-create command.

7. Registration of @sign in your private dess

At this step you should already have your @sign registered at http://atsign.com. If not go do it!

I have registered my own free @sign (@44likelycanary) which I will link to my dess.

In your instance console, navigate to dess folder. If you were following this guide it will be located in:

We now need to create the service that will host our @sign by executing the dess-create command:

$ sudo dess-create @44likelycanary 4atsign.link 8000 <email address> likelycanary

To make it more understandable:

I will be registering my @sign @44likelycanary.

I will be using my domain 4atsign.link which I have registered through AWS.

I am using port 8000 which I have opened in my instance firewall.

My registration email address is <email address> (this email is used to sign the SSL certificates).

The last likelycanary is the name that docker will use to track the service.

If everything is successful you should see output like this:

img

At this moment your @sign is registered on your dess.

8. Activation of @sign

Next up we need to activate it

Login to your dashboard at https://my.atsign.com/dashboard

Open “my @signs”

gcp-atsign-dashboard

Open “managed” of @sign you are registering”

gcp-atsign-nonactive

Navigate to Advance settings:

gcp-atsign-active

If you have already activated your @sign you will be prompted to erase all your data first

gcp-atsign-erase

Once done you are able to link your @sign with your private dess. Use your domain and port number with which you have created service on your cloud instance and press Activate

image-20210617111907819

You should see that your @sign is being activated in your dashboard:

gcp-atsign-activating

The activation will be completed once you have used your QR code from dess and retrieved your keys.

Once the activation process completes you are welcomed by green Activated.

gcp-atsign-activated

CONGRATULATIONS

6.2 - The @platform data privacy & permissions guide

The @platform data privacy and principles which assure that people always have control over their data

Application Access to Data

There are three basic types of application data access:

  1. Storing and retrieving data for your application
  2. Accessing data shared by others
  3. Accessing and reasoning over data stored by other applications

Storing and retrieving data for your application

If your application needs to store data, you can use the @SDK to manage data securely and easily in the @persistence keystore. This SDK provides the following capabilities:

  • Data is stored in an encrypted keystore locally for your application
  • Data access is in-memory and super-fast
  • Offline access with the device is supported
  • Data is synchronized and backed up to a cloud @server automatically
  • Data is synchronized across all the person’s devices automatically
  • Privacy is hardcoded: The owner of the data controls all access to it

Note: the cloud @server does not have access to the secret private key. This prevents bad actors from accessing or modifying private data not meant for them.

Creating, updating and deleting data with your application

Data operations that involve writing data to the @persistence keystore can only be done with the approval of the owner. Access to this data is cryptographically controlled. This is managed for your application by the @SDK and is remarkably easy. The types of access that can be set for each data record include:

  • public: data that can be read by anyone without need for authentication
  • shared: data that the owner has explicitly granted the right to some entity to read it after proving they are who they claim to be
  • private: data that is only accessible to the owner (requires authentication)
  • hidden: publicly readable data that is not listed in a scan of the keystore.

Naturally, the owner of an @persistence keystore has access to any and all data that is contained therein. After being authorized, your application can read the data that it needs from the keystore as well. Applications that prefer to rely on data within its own namespace can also store read data from the @persistence keystore with approval of the owner. As always, all data stored is owned and controlled by the owner of the @persistence keystore.

For more information on how your application can create, update, or delete data, see the @Persistence Keystore Guide and the @Protocol Verbs.

Accessing data shared by others

Applications typically are a combination of an owner’s data and data that has been shared with them by others. This is a new feature and is what we’re referring to when we talk about P2P (Peer-to-Peer) applications.

For example, messaging applications available today involve a combination of data (messages) from various people but have no way to ensure that each individual message belongs to its creator. With the @protocol, messages that I create and share with other people are owned by me and likewise, messages that others create and share with me are owned by them. The messaging application is thus responsible for interleaving and presenting these messages while simultaneously maintaining privacy controls for the owner of the data (i.e. I own my messages to you and you own your messages to me).

While this may seem confusing and difficult at first, the @Client SDK and the Flutter UI Component libraries make it very simple to implement. This results in surveillance-free, privacy-compliant applications that are simple, cost-effective, and efficient, with better performance than backend server-based applications of the past.

The @Client SDK provides the following capabilities that help to integrate data shared by others in your application:

  • Public data shared by others can be looked up
  • The notification verb alerts your application when new data shared by others is available
  • The monitor verb creates a persistent connection for real-time interactions
  • Data can be scanned for and read directly from another persons @persistence keystore
  • Shared data is cached for fast, reliable access to shared data with all privacy related parameters managed for you by the @Client SDK

For more information on how your application can create, update, or delete data, see the [@Persistence Keystore Guide](Persistence Keystore Guide) and the @Protocol Verbs.

Accessing and reasoning over data stored by other applications

One super interesting side effect of giving people control of their data and storing it all in one place is that any application that they authorize can reason over any data that they are allowed to access. Applications that are certified as @protocol compliant (@pps) can provide amazing new experiences because they have the ability to access and reason over all data stored in an @persistence keystore.

For example, a certified messaging app may contain a thread where a group of people are discussing which movie to go see on Wednesday night. If permitted, this information can also be presented as an event in their certified calendar application and similarly presented as a group in their certified contacts application.

Advanced Options

Create a separate @persistence keystore for your application (certification not required)

If you would like to store application data, you are free to use the @persistence keystore for your persistence if you want to. You may want to get your application certified anyways to advertise that it is privacy compliant and have it included in our list of certified apps.

Authentication only, without the @persistence keystore (certification not required)

If your application does not require data persistence on behalf of the person using it; for example, if you just want to make sure that your application is licensed to the person using it, then you do not need to get it certified. You may want to get your application certified anyways to advertise that it is privacy compliant and have it included in our list of certified apps.

For more information about getting your application certified, see the Certification page.

6.3 - The @platform persistence keystore guide

How to use the @platform encrypted key/value store

Application data storage

Data for your application is the combination of the device owner’s data with data that has been shared by others. An @sign owner’s data is…

  • Stored in the the @sign owner’s device’s (local) @persistence keystore
  • Accessed by others via their internet addressable, always-on, secure, cloud (remote) @server
  • Backed up in their secure cloud (remote) @server
  • Synchronized between their cloud (remote) @server and any other devices that belong to the owner
  • Secured by secret keys which are only stored on the @sign owner’s device’s keychain

Note: The @sign owner’s cloud (remote) @server does not hold the owner’s secret key, which is required to make changes to the data. The local @server on the owner’s device must initialize any data changes.

Data that others have shared with an @sign owner is…

  • Accessed directly from their secure cloud (remote) @server with full privacy controls so it is always up to date
  • Cached on the @sign owner’s device’s local keystore if permitted
  • Removed from the @sign owner’s device’s local keystore automatically according to the permissions set by the owner of the data
  • Updated upon change automatically using the notification verb

How application data is stored and retrieved

As mentioned above, data is stored encrypted as a key/value pair. The @Client SDK supports a familiar set of methods to store and retrieve data from an @persistence keystore. You should always keep in mind that the @protocol includes strict privacy controls applied to all data in an @persistence keystore.

Application Access

Apps can reason over all of my data in my @persistence keystore

One super interesting side effect of giving people control of their data and storing it all in one place is that any application that they can choose to reason over any data that they are allowed to access in order to create altogether new user experiences.

For example, their certified messaging application may contain a thread where a group of people are discussing which movie to go see on Wednesday night. If permitted, this information can also be presented as an event in their certified calendar application as well as a group in their certified contacts application.

Access within an application namespace

Applications that only rely on data within its own namespace can also store data in the @persistence keystore if certified as @protocol compliant. If the data being stored rightfully belongs to the person creating it (which is the case most of the time), then they will have control of how it is used and shared with other entities and applications.

Use a separate @persistence keystore for your application (certification not required)

If you would like to store application data, you are free to use the @persistence keystore for your persistence if you want to. You may want to get your application certified anyways to advertise that it is privacy compliant and have it included in our list of certified apps.

Authentication only, no need to use the @persistence keystore (certification not required)

If your application does not require data persistence on behalf of the person using it; for example, if you just want to make sure that your application is licensed to the person using it, then you do not need to get it certified. You may want to get your application certified anyways to advertise that it is privacy compliant and have it included in our list of certified apps.

For more information about getting your application certified, please see the Certification page.

6.4 -

Contributing to an Open-Source GitHub Project

Overview:

There are a countless number of open source projects that exist on the Internet, but just how are you meant to add anything to these? What does forking a repository mean? What is a pull request? How can you make a contribution?

What is an open source project?

For anyone who is new to not just software development but project management in general, an open source project is that of which any person has access to all of the details of the project and are free to utilize it, use it for research purposes, make modifications to it, and even distribute it elsewhere. GitHub of course, being one of the main wellsprings of open source projects! For the sake of this article, I will be using The @ Company’s atsign-foundation repository to explain any examples.

Why would you want to contribute to an open source project?

With the new, blossoming field of data science, being capable of finding your way around a GitHub project is a significantly useful skill in today’s world. You’ll find that many corporate entities will highlight your contributions to any GitHub project (as long as you have listed them within your résumé!). You’ll also find that there are many friendly developers who really appreciate the people who add modifications to the project, and especially if that modification comes with a flagged issue (there seems to be a special place in the heart of a developer for people who raise issues within their code)! There’s also this sense of great accomplishment when you can add something useful to a project, more importantly, for the projects that you use often.

How can you contribute to an open source project?

Choosing a Project:

The first step in contributing something to a project is knowing what project you will contribute to! I’d personally recommend thinking about a project or an idea you have familiarity with as this will greatly assist in understanding what the project’s purpose is.

Forking a Repository:

What is forking? In simplest terms, forking a project is simply making a copy of it to your own GitHub profile. GitHub allows anyone to fork a repository and this will allow you to do whatever you please with the entire repository without making any actual changes to the real project! Imagine it as taking a picture of a tree. You can make edits to your photo to make the tree look purple or to give it a face, but you won’t make any changes to the actual tree!

How to Fork a Repository:

First, navigate to the home page of the repository you wish to fork. Refer to the screenshot below:

Here, you can see that I am currently within the atsign-foundation’s ‘at_demos’ repository.

fork-button

If you look at the top right corner of the repository’s page, you’ll notice the ‘Fork’ button and a number next to it. That number represents the number of times this specific repository has been forked. Once you select the Fork button, GitHub will prompt you which repository you wish to fork to. My go-to option is typically my own profile, where it will create an entire repository under your profile name so that you may make whatever modifications you wish. After you choose what location you wish to fork to, GitHub will do all of the hard work for you. After a few seconds or so (depending on your Internet connection speed), you’ll find that the entire repository that you forked, is now copied to wherever you told GitHub to fork it! Congratulations! You’ve forked a repository!

Make Modifications to the Repository:

Now, you can do whatever your heart so desires with the project! Depending on what the project is, you may wish to clone the repository to your local machine using https/, or simply commit changes directly on your forked repository (totally your choice/preference!).

Creating a Public Key with GitHub

We recommend git cloning the repository using the SSH key option. You can set up your own public keys on GitHub quite easily. If you see below, you will see the Clone options, ‘HTTPS, SSH, and GitHub CLI’. Select the ‘SSH’ option and this will provide you a password-protected SSH key to git clone the repository.

GitHub-Code-Options

In order to create a public key on your machine, open any UNIX terminal and type the command:

ssh-keygen

From here, it will ask you to choose a lcoation to store the key. We suggest just clicking ‘enter’ on whatever location is chosen for you. It will then ask for a passphrase, we STRONGLY recommend clicking ‘enter’ again to not input a passphrase. After doing this, it will ask you to input the passphrase again and click ‘enter’ without inputting anything. After having successully creating the key, enter the command:

cat ~\.ssh\id_rsa.pub

This will print out your public key. Copy the entire thing, including the ssh in the beginning and whatever the final character is and navigate to your GitHub settings page. Within your settings, you will see a tab titled, ‘SSH and GPG keys’. Once you navigate to this page, you should see a green bottom near the top-left titled, ‘New SSH key’. Once you have clciked this and navigated to the new SSH Key page, you will have to input a name for the key as well as pasting the retrieved key copied from the above command. After you have done both of these things, you can finish with the ‘Add SSH key’ button and you will now be able to git clone in your terminal with the SSH URL.

Create a Pull Request:

After you are satisfied with the changes you have made to the project and are confident that this change will be beneficial to include, all you now have to do is create a pull request within the project’s real repository. GitHub has made it very simple to create a pull request for comparing forks. Refer to the screenshot below:

pull-request

You may notice, in the top left corner of the repository, you will see the ‘Pull requests’ option. After selecting this, you will be taken to the Pull Requests page. This page will show you every pull request that has been created for the specific repository. If you see below, there has been one pull request for this repository thus far.

pull-request-page

If you are sure you are ready to create a new pull request, simply click the ‘New pull request’ button. This will then navigate you to the compare page. If you followed the above steps, you would want to ‘compare forks’, which will be a small hyperlink as circled below:

compare-changes

This will now change the base and head repositories that will be compared. Be sure to select the correct branch of the real project that you wish to make a pull request for. Select the same repository you forked and the correct branch as the ‘base’ repository and ‘base’ branch. You may need to contact the project leader or one of the main developers if you need assistance for which branch you need to make a pull request for. After selecting these, be very careful in selecting the repository that you forked. This will be where you had made the modifications. Select this repository as the ‘head’ repository and ‘compare’ branch.

review-mods

From here, you will see all of the modifications that will occur if your pull request is accepted. Once you double check all of these modifications and are confident in it, you may now select ‘Create pull request’. You may notice that mine says ‘View pull request’ but that is because I have already gone through this process and have successfully created one.

Side note: Be sure that your contribution will be useful for those who utilize the project! If you do end up creating a pull request with your modifications, make sure that those modifications are properly documented in both the code and/or the comment section of the pull request itself.

6.5 -

Working With Hugo (Static Webpage Generator)

Overview:

Hugo, an open-source static website generator, is a new way to create web pages easily with flexible thematic capabilities. How do you get started with it and how can you go from beginner to confident?

What is Hugo?

Hugo is a static site generator that can be seen as a competitor for WordPress and Bootstrap. The best part about Hugo that differentiates it from its competitors is that it is an open-source project, which means it’s free to use! Hugo also makes content management a headache-free, comprehensive process! Hugo can be incredible for this type of content management due to not even needing to write HTML if web development is not something you’re comfortable with! If you are the type who really enjoys getting your hands dirty, Hugo’s flexibility expands to allowing developers to completely modify everything about their own static web page. Now what’s a static web page? You can pretty much sum it up to be a hard-coded page of information that, of course, does not change dynamically. The best advantage that static web pages have over dynamic web pages is the extreme difference in speed. Because most dynamic websites are producing content for the individual visitor, it can take much longer to produce the content.

There’s a growing community behind Hugo with numerous Stack Overflow locations with any questions relevant to that of Hugo. Getting Started with Hugo:

Windows:

Installing Hugo on Windows:

There are a few ways in which you can get started with Hugo, however the easiest way I have found to getting started and jumping straight into things is by the following steps:

Create a directory in a location on your drive. For me, I have more storage capacity within my D: drive so I navigate to my D: drive within my File Explorer and simply right click and select ‘Folder’. This will create a new folder wherever you were within your drive. Next, rename this folder to ‘Hugo’. After this, navigate inside of your Hugo folder and create another folder within it, this time calling it ‘bin’.

You’re now ready to download Hugo on to your machine. As most projects which are open-source can be found on GitHub, so can Hugo’s releases. In any web browser, navigate to the GoHugoIo repository. Here, you will find a great list of all of the releases catered for Windows, Linux, and MacOS. Be sure to select a release that has your operating system in the title. For example, I am using a Windows 10 machine that runs a 64 bit processor. So I navigated to the zip file titled hugo_extended_0.83.1_Windows-64bit.zip. (Note: the release number may be different from the one listed above due to the time at which I have written this document. You may also noticed that I have chosen the extended Hugo version. Hugo extended has more capabilities, especially for thematic purposes. Hugo’s extension comes with a few advantages such as; SASS/SCSS support, Minify javascript and css, resource catenation, source mapping, image processing and so much more. A more in depth view of it can be found here.

Once you have found the matching release title for your machine, feel free to simply download the zip file. Where you download the zip file does not matter, however, where you extract it does. When your download is complete, select ‘Extract all’ and be sure that you extract the contents of what you downloaded into the ‘bin’ folder that exists within your Hugo folder. Once the extraction is complete, it should look something like this:

bin-folder

For the release that I have downloaded and extracted, there are three files. Perhaps in a later release of Hugo, there may be more files included, but for now, as long as you have the application file titled ‘hugo’, you will be fine. If, for whatever odd reason, the ‘hugo’ file is titled something else, be sure to rename it to ‘hugo’ (note the lowercase ‘h’). There is also a license file and a readme. It is completely up to you if you read the readme and license files.

Determining if your Installation on Windows was successful:

Apologies in advance for MacOS and Linux users as I will be demonstrating the following steps using a Windows 10 machine. A later edit with both MacOS and Linux will be created to cater those who wish to learn from a separate operating system. To make sure that your Hugo was successfully installed and extracted, open your command prompt [Some ways in which this can be done => (Win key + r, type ‘cmd’, hit ‘enter’), (Go to your Search bar and the bottom of your taskbar and type in ‘cmd’ or ‘command prompt’ and hit ‘enter’)] and navigate to the directory where you extracted Hugo. For the above picture, my hugo.exe file’s location was D:\Hugo\bin\hugo.exe, so all I have to type is ‘cd D:\Hugo\bin’ and I will be taken to where the hugo.exe exists. If you’re not sure where you had saved your Hugo folder, you can either use the File Explorer you have presently open and simply highlight the path that is in the bar above your currently open Hugo folder. I have circled it below for your convenience.

file-location

To show what your command prompt should look like: hugo-location

Once you are here, feel free to try the command ‘hugo version’: hugo-version

If your command prompt happily prints out the current version of Hugo you have on your machine, this means you have successfully installed and extracted Hugo onto your machine. However, you may notice that if you use the command ‘cd ..’ to move directories to the ‘Hugo’ folder rather than ‘bin’ and try the command ‘hugo version’ you will be hit with an error or Windows will tell you that hugo isn’t a recognized command. hugo-error

If you are like me, and wish to be capable of using the hugo command anywhere on your machine, maybe because you would like to create a web page with its own folder and its own content, there is an easy way to fix this.

What you will have to do is navigate to your ‘Search’ bar and type in ‘env’ or ‘environment’. Windows will suggest the ‘Edit the System Environment Variables’. Open it and a System Properties dialog box should appear and look something like this: env-variables

Double-click on the button labeled ‘Environment Variables’ and this will open the dialog box where you can edit the environment variables of your machine. You may be wondering what environment variables are and what they’re for. In simplest terms, just like how you noticed that your hugo command did not work outside of the bin folder, there are other applications that work the same way and will only work in the folder they exist in. Windows has the capability of allowing you to run the application from anywhere, which is exactly what we would like to do. You should see something in your ‘user variables’ called Path. Each Path that is listed, is more than likely an application, similar to your Hugo, that exists only in a folder but is used globally on your machine. Highlight ‘Path’ and click ‘Edit…’. This will open a new dialog box that will list the individual paths that already exist. Click ‘New’ and simply type (or paste) the location of your hugo.exe. If you may recall from my example, my hugo.exe was in the following location; D:\hugo_ext\bin.

hugo-path-edit

Here’s what mine looks like after I have finished typing in where it exists (it is the one highlighted in blue). After you have done the same, you can now click ‘OK’ until all of the dialog boxes are closed. Now this is where the magic happens! After restarting your computer, try using the ‘hugo version’ command again outside of the ‘Hugo\bin’ folder and see if Windows recognizes it as a command! I simply started up my command prompt and immediately typed in ‘hugo version’ and it worked. If the command works, you are now ready to get started on a Hugo project.

Hugo-Version-Outside-Bin

Mac:

Installing Hugo on Mac:

The first step you will want to take is navigating to the website Homebrew. This website is a package manager and allows you to install, download and manage packages. You can use Homebrew to install Hugo easily on your computer. Once you are taken to the landing page, you should come across a terminal command that looks like:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

// NOTE: // This command may be updated depending on any new releases, // so be sure to check the website before copying the line of code above!

Simply paste the line of code into your terminal. Once you click enter and input your password for administrative access, Homebrew will begin installing itself onto your machine. This can take a few minutes. Once Homebrew is finished, you can then type the command:

brew install hugo

Homebrew may update itself automatically before installing hugo.

Determining if your Installation on Windows was successful:

You can validate your install by the command:

which hugo

You can also use the command:

hugo version

If you run into an error, proceed through the Windows steps and follow the instructions up until the GitHub section where you manually install the package from the repository for your own machine.

Creating a Hugo project:

Depending on your operating system, open your command prompt/terminal. You can also launch an IDE of your preference and have the terminal open within it. To create a new hugo project, be sure that you are within a directory that you would want to have your Hugo project created in. For this article, I will create a new folder within my D: drive (Windows) and then use the command:

hugo new site your_name_here

Refer to the steps within my command prompt below: I first check that my hugo command works, change directory into my D: drive, create a new folder called, ‘my_hugo_site’, navigate into that folder, and then create a new Hugo site called, ‘my_hugo_project’.

Hugo-New-Site

If you receive the ‘Congratulations!’ message, this means that you have successfully created a new Hugo site. If you expand the project folder to see its contents, you will see that a few folders have been created. (Be sure that you navigate within your newly created project first!)

Hugo-Project-Folders

The number of folders created here may seem a bit overwhelming, but have no fear! We will go over what each folder is for.

Archetypes:

The first folder is the ‘archetypes’ folder. This folder is typically used by those more confident with Hugo. An archetype, in its simplest form, is simply a constant that occurs throughout all of the content of your website, something that will not change. With Hugo, you can manually create data about your site (for you Computer Scientists, that’s metadata!). What this means is that you can assign values to things that will not be changing. This could mean, who initially created the website, what date it was created, what information populates the site itself, and etc.

Content:

A very self explanatory folder, this is where the main content of your site will exist.

Data:

You can almost view this as your website’s own database which can house .json files and allows you to utilize information that exists within external pieces.

Layouts:

Just like a word document, if you wish to add information within the same location of every page that exists on your website, such as a header or a footer, this is where you would add that.

Static:

This is, of course, where your static elements will exist. These elements may include your javascript or css files.

config.toml:

This file contains the settings of your website, such as its URL, what language it contains, and the title of the website.

Themes:

If graphic design isn’t one of your strengths, Hugo being an open-source project means that there are countless persons releasing their own themes and layouts for you to use! You can browse these themes here. Installing a theme is just as simple as downloading a folder to your machine, because that is exactly what you are doing! You may notice that every theme which peaks your interest will also exist on GitHub. You can use whatever method you prefer to retrieve the code. In this document, I will demonstrate a couple ways to do this. Once you find a theme that suits your needs or ‘aesthetic’, simply click on the theme. You may see two or three buttons, ‘Download’, ‘Demo’, ‘Homepage’. If you are confident that this is the theme you want, click ‘Download’ and it will take you to the GitHub repository where the theme exists. Click on the green ‘Code’ button and this will give you a few options on how to retrieve the code.

Git-Clone-Theme

For this example, I have found a theme that interests me titled ‘Dream’. For users who have Git, you can copy the https link and navigate into the ‘themes’ folder of your project to git clone it. Refer to the screenshot below (I am using Git Bash):

Git-Clone-Theme

When you clone the repository, it will automatically create a folder for you. However, if you are not sure how to use Git, you can simply download the Zip file onto your machine. Before installing this zip folder, be sure to create a folder within your ‘themes’ folder with the appropriate title of the theme you are downloading. After downloading the zip folder, you should extract the contents into the folder that you just created inside of your ‘themes’ folder. You can see in the screenshot below, that the folder ‘hugo-theme-dream’ exists within the ‘themes’ folder.

Theme-File-Location

After successfully implementing the above steps, navigate into your config.toml file and add the line of code below everything else that exists in the file:

theme = “folder_name_here”

So, in my case, I would type the following:

theme = “hugo-theme-dream”

After adding this line, save the document and to make sure that you have properly called this theme into your site use the following command in your command prompt/terminal to start up your Hugo local server:

hugo server -D

The -D will launch all of the draft pages that exist within your project folder.

After this, you can now open any web browser and type in the URL:

localhost:1313

You should now see your website and the theme you installed! From here, if you wish to contrbute, I recommend reading through our ‘Contributing to an Open-Source Project’ document!

Steps for Setting up our hugo dev site on your machine

  1. Since I have already created a fork of the atsign.dev repo, all I simply have to do is fetch the upstream for any recent changes made.

  2. I then proceed to git pull the updated forked repo (or if you haven’t already simply git clone it).

  3. You now need to edit the config.toml file so that your theme = “at_docsy”

  4. Get the https:// link from the at_docsy repo on our GitHub

  5. If you are using Git Bash all you have to do is navigate within the atsign.dev folder that contains the folders; content, archetypes, assets, etc. and use the command:

git submodule add "https://github.com/atsign-foundation/at_docsy.git" themes/at_docsy

This command will pull the at_docsy repo’s contents and add them to a created folder titled at_docsy under your themes folder

  1. Finally, use the command below and you will be ready to use the hugo commands:
git submodule update --init --recursive 

7 - @platform Additional Resources

All the resources you will need for developing on the @platform

7.1 - The @client/AtClient SDK Cookbook

This cookbook contains recipes that demonstrate how to solve common problems while writing apps that implement the @protocol. Each recipe is self-contained and can be used as a reference to help you build up an application.

The Verb tree

Before we look at some of the sample code, the verb tree gives you a big picture of all of the verbs and what can be executed where.

alt_text

1. Scan

The scan verb is used to scan the available @ addresses for you either at the public level or all authorized data once the pol process has been completed. This allows addresses to be discovered and perhaps be harvested so if an address has a _ character as its first character then it is omitted from the scan list although it can still be looked up if known. The following example shows just that.

Following are the steps to run the scan verb using the @Client SDK

  1. Get an instance of AtClient
  2. Execute the scan verb using the AtClient

1.1 Get an instance of AtClient

To get an instance of the AtClient by calling the getClient method on the Client Impl class.

import 'package:at_client/at_client.dart';
import 'package:at_client/src/client/at_client_impl.dart';

void main() async  {
  
  // Construct  AtClientPreference
  var preference = AtClientPreference();
  preference.hiveStoragePath = '/hive/storage/path';
  preference.commitLogPath = '/commit/log/path';
  // Namespace is mandatory to be passed. E.g me, buzz, etc.,
  await AtClientImpl.createClient('@bob','me', preference);
  var atClient = await AtClientImpl.getClient('@bob');
}

1.2 Execute the scan verb using @AtClient

a.Simple Scan - Returns all keys
// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob);
// Scans keys stored in app storage
await atClient.getKeys();
b.Scan keys matching a regular expression
// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob);
// Scans keys in .me namespace
await atClient.getKeys(regex:'.me');
c.Scan keys shared with another atSign
// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob);
// Scans keys shared with @alice
await atClient.getKeys(sharedWith:'alice');
d.Scan keys shared by another atSign
// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob);
// Scans keys shared by @alice. This performs authenticated scan on @alice's secondary.
await atClient.getKeys(sharedBy:'alice');

2. Update

Update verb used to add entries in the @server. @signs have to be authenticated for one to run the update verb on the @server.

Following are the steps to run the scan verb using the @Client SDK

  1. Get an instance of AtClient
  2. Execute the update verb using the AtClient

2.1 Get an instance of AtClient

To get an instance of the AtClient by calling the getClient method on the AtClientImpl class.

import 'package:at_client/at_client.dart';
import 'package:at_client/src/client/at_client_impl.dart';

void main() async  {
  
  // Construct  AtClientPreference
  var preference = AtClientPreference();
  preference.hiveStoragePath = '/hive/storage/path';
  preference.commitLogPath = '/commit/log/path';
  //create atClient
  var atClient = await AtClientImpl.createClient('@bob', 'me', preference);
}

2.2 Execute the update verb using AtClient

// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob');
// create phoneKey
var phoneKey = AtKey()..key = 'phone';
// Update a phone number visible only to @bob
await atClient.put(phoneKey, ''+1-123-4567');
// create emailKey
var emailKey = AtKey()..key = 'email'
                      ..sharedWith = '@alice';
// Update an email visible only to @alice
await atClient.put(emailKey, 'bob@atsign.com');
// Update an email visible only to everyone
// create metadata with isPublic true
var metadata = Metadata()..isPublic=true;
// create emailKey and update metadata
var emailKey = AtKey()..key = 'email'
                      ..metadata = metadata;
await atClient.put(emailKey, 'bob@gmail.com');
// Update a location that expires in 10 minutes
 var metadata = Metadata()..ttl=600000;
var locationKey = AtKey()..key = 'current_location'
                      ..metadata = metadata;
await atClient.put(locationKey, 'https://goo.gl/maps/Trs5Dao562tLFK5Q9');

3. Lookup

The lookup verb is used to lookup a value on a @server of another @sign. The following demonstrates the use of lookup verb.

Following are the steps to run the scan verb using the @Client SDK

3.1 Get an instance of AtClient

To get an instance of the AtClient by calling the getClient method on the AtClientImpl class.

import 'package:at_client/at_client.dart';
import 'package:at_client/src/client/at_client_impl.dart';

void main() async  {
  
  // Construct  AtClientPreference
  var preference = AtClientPreference();
  // Get 
  var atClient = await AtClientImpl.createClient('@bob', 'me', preference);
}

3.2 Execute the lookup verb using AtClient

// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob');
// Look up phone number sharedBy @alice
//lookup:phone.me@alice
var atKey = AtKey()..key = 'phone'
                   ..sharedBy = '@alice';
await atClient.get(atKey);

4. Plookup

The plookup verb is used to lookup a public value on a @server of another @sign if the client is authenticated. Plookup verb can only be executed on a remote @server. The following demonstrates the use of plookup verb.

Following are the steps to run the scan verb using the @Client SDK

4.1 Get an instance of AtClient

To get an instance of the AtClient by calling the getClient method on the AtClientImpl class.

import 'package:at_client/at_client.dart';
import 'package:at_client/src/client/at_client_impl.dart';

void main() async  {
  
  // Construct  AtClientPreference
  var preference = AtClientPreference();
  //Get 
  var atClient = await AtClientImpl.createClient('@bob', 'me', preference);
}

4.2 Execute the plookup verb using AtClient

// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob');
// plookup public phone number of @alice
var metadata = Metadata()..isPublic=true;
var publicPhoneKey = AtKey()..key = 'phone'
                            ..sharedBy = '@alice'
                            ..metadata = metadata;
await atClient.get(publicPhoneKey);

5. Llookup

The llookup verb is used to lookup a value on a local @server storage of current @sign. The following demonstrates the use of llookup verb.

5.1 Get an instance of AtClient

To get an instance of the AtClient by calling the getClient method on the AtClientImpl class.

import 'package:at_client/at_client.dart';
import 'package:at_client/src/client/at_client_impl.dart';

void main() async  {
  
  // Construct  AtClientPreference
  var preference = AtClientPreference();
  preference.hiveStoragePath = '/hive/storage/path';
  preference.commitLogPath = '/commit/log/path';
  //Get 
  var atClient = await AtClientImpl.createClient('@bob', 'me', preference);
}

5.2 Execute the llookup verb using AtClient

// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob');
// Local lookup a self key e.g @bob:email.me@bob
var privateEmailKey = AtKey()
 ..key = 'email'
 ..sharedWith = '@bob';
var alicePrivateEmail = await atClient.get(privateEmailKey);
// Local lookup phone shared with @alice e.g @alice:email.me@bob
var phoneKey = AtKey()
 ..key = 'phone'
 ..sharedWith = '@alice';
await atClient.get(phoneKey);
// Local lookup a public key 
var metadata = Metadata()..isPublic=true;
var firstnameKey = AtKey()
 ..key = 'firstname'
 ..metadata = metadata;
await atClient.get(firstnameKey);
// Local lookup a key ignoring namespace
var metadata = Metadata()..namespaceAware=false;
var firstnameKey = AtKey()
 ..key = 'firstname'
 ..metadata = metadata;
 await atClient.get(firstnameKey);

6. Delete

The “delete” verb is used for deleting @addresses.

Following are the steps to run the scan verb using the @Client SDK

6.1 Get an instance of AtClient

To get an instance of the AtClient by calling the getClient method on the AtClientImpl class.

import 'package:at_client/at_client.dart';
import 'package:at_client/src/client/at_client_impl.dart';

void main() async  {
  
  // Construct  AtClientPreference
  var preference = AtClientPreference();
  preference.hiveStoragePath = '/hive/storage/path';
  preference.commitLogPath = '/commit/log/path';
  // create AtClient 
  var atClient = await AtClientImpl.createClient('@bob', 'me', preference);
}

6.2 Execute the delete verb using AtClient

// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob');
// delete self key e.g @bob:phone.me@bob
var phoneKey = AtKey()..key = 'phone'
                      ..sharedWith = '@bob';
await atClient.delete(phoneKey);
// delete email shared with @alice e.g @alice:phone.me@bob
var phoneKey = AtKey()..key = 'phone'
                      ..sharedWith = '@alice';
await atClient.delete(phoneKey);

// delete a public key e.g public:phone.me@bob
var metadata = Metadata()..isPublic=true;
var phoneKey = AtKey()
 ..key = 'phone'
 ..metadata = metadata;
await atClient.delete(phoneKey);

7. Stats

The “stats” verb is used to get certain predefined statistics from the @server.

7.1 Get an instance of AtClient

To get an instance of the AtClient by calling the getClient method on the AtClientImpl class.

import 'package:at_client/at_client.dart';
import 'package:at_client/src/client/at_client_impl.dart';

void main() async  {
  
  // Construct  AtClientPreference
  var preference = AtClientPreference();
  preference.hiveStoragePath = '/hive/storage/path';
  preference.commitLogPath = '/commit/log/path';
  // Get 
  var atClient = await AtClientImpl.createClient('@bob', 'me', preference);
}

7.2 Execute the stats verb using AtClient

// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob');
// Execute the verb e.g stats:1,stats:1,2 etc.,
// You can use stats number from 1 to 10
// If you want to request multiple types use as , separated values
// Ex: stats:1,2,5
await atClient.getRemoteSecondary().executeCommand('stats:1');

8. Config

The “config” verb is used to configure block list entries in the @server. If an @sign is added to the block list then connections to the @server will not be accepted.

Following are the steps to run the scan verb using the @Client SDK

  1. Get an instance of AtClient
  2. Set up a ConfigVerbBuilder & execute the verb using the AtClient

8.1 Get an instance of AtClient

To get an instance of the AtClient by calling the getClient method on the AtClientImpl class.

import 'package:at_client/at_client.dart';
import 'package:at_client/src/client/at_client_impl.dart';

void main() async  {
  
  // Construct  AtClientPreference
  var preference = AtClientPreference();
  preference.hiveStoragePath = '/hive/storage/path';
  preference.commitLogPath = '/commit/log/path';
  // Get 
  var atClient = await AtClientImpl.getClient('@bob', preference);
}

8.2 Set up a ConfigVerbBuilder & execute the verb using the AtClient

// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob, AtClientPreference());
var builder = ConfigVerbBuilder()..block = '@rachel';
// Execute the verb
await atClient.getLocalSecondary().executeVerb(builder);

9. Notify

The “notify” verb is used to notify another @server of change related to a @address.

Following are the steps to run the notify verb using the @Client SDK

  1. Get an instance of AtClient
  2. Set up a NotifyVerbBuilder
  3. Execute the scan using the AtClient

9.1 Get an instance of AtClient

To get an instance of the AtClient by calling the getClient method on the AtClientImpl class.

import 'package:at_client/at_client.dart';
import 'package:at_client/src/client/at_client_impl.dart';

void main() async  {
  
  // Construct  AtClientPreference
  var preference = AtClientPreference();
  preference.hiveStoragePath = '/hive/storage/path';
  preference.commitLogPath = '/commit/log/path';
  // Get 
  var atClient = await AtClientImpl.getClient('@bob');
}

9.2 Execute the notify verb using AtClient

// Create Atclient Instance
await AtClientImpl.createClient('')
// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob);
var atKey = AtKey()
..key = 'phone@bob'
..sharedWith = '@alice'
..sharedBy = '@bob'
// Execute the verb
await atClient.notify(atKey, '+1 987 986 2233', OperationEnum.update);
// Sending Notification with Notification Strategy 'ALL'
await atClient.notify(atKey, '+1 987 986 2233', OperationEnum.update, 
                      priority: PriorityEnum.low,
                      strategy: StrategyEnum.all);

// Sending Notification with Notification Strategy 'Latest N'
await atClient.notify(atKey, '+1 987 986 2233', OperationEnum.update, 
                      priority: PriorityEnum.high,
                      strategy: StrategyEnum.latest,
                      latestN:3,  
                      Notifier: 'wavi');                                               

9.3 Execute the notify status verb using AtClient

// Create Atclient Instance
await AtClientImpl.createClient('')
// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob);
var atKey = AtKey()
..key = 'phone@bob'
..sharedWith = '@alice'
..sharedBy = '@bob'
// Execute the notify verb
var notiticationId = await atClient.notify(atKey, '+1 987 986 2233', OperationEnum.update);
// get notification status of the above notificationId
var status = await atClient.notifyStatus(notificationId);                                              

10. Monitor

The “monitor” verb is used to stream incoming notifications from the @server to @Client.

Following are the steps to run the notify verb using the @Client SDK

  1. Get an instance of AtClient
  2. Execute the monitor using the AtClient

10.1 Get an instance of AtClient

To get an instance of the AtClient by calling the getClient method on the AtClientImpl class.

import 'package:at_client/at_client.dart';
import 'package:at_client/src/client/at_client_impl.dart';

void main() async  {
  
  // Construct  AtClientPreference
  var preference = AtClientPreference();
  preference.hiveStoragePath = '/hive/storage/path';
  preference.commitLogPath = '/commit/log/path';
  // Get 
  var atClient = await AtClientImpl.getClient('@bob', preference);
}

10.2 Execute the monitor verb using AtClient

// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob');
var builder = MonitorVerbBuilder();
// Execute the verb
await atClient.startMonitor(<privateKey>,<NotificationCallback>);

//Using Regex on Monitor verb
// Get an instance of AtClient for @bob
var atClient = await AtClientImpl.getClient('@bob');
var builder = MonitorVerbBuilder();
// Execute the verb
await atClient.startMonitor(<privateKey>,<NotificationCallback>,regex: '.wavi');

Verb Parameter Reference

required optional’*

VerbParameters
fromatSign* - @ sign you claim to be
cramdigest* - SHA512 digest
pkamsignature* - Signed challenge
polNA
scanforAtSign - Scans the keys shared by forAtSign

regex - Regex to which the @addresses has to be matched to be returned as a result

updatettl - Time to live in milliseconds. Value for the key won't be available after the ttl’

ttb - Time to birth in milliseconds. Value for the key will be available after the ttb’

Scope - Public vs Private

forAtSign* - For whom the value is being set

atKey* - Name of the @address

value* - Value for the @address

lookupatKey* - Name of the @address

atSign* - @ signs namespace

llookupatKey* - Name of the @address

atSign* - @ signs namespace

plookupatKey* - Name of the @address

atSign* - @ signs namespace

deleteatKey* - Name of the @address
statsstatId - Id’s of the statistics to display
configwhatToConfig* - Thing to configure

configValue* - Value of the thing to configure

notifyforAtSign* - @sign to notify

key* - Key to which the change has happened

change* - Change it self

monitorregex - Regex that needs to be matched for the value to be monitored

7.2 - The @platform Glossary of Terms

Definitions of terms and acryonms often used with the @platform

@platform :

The @platform is an open development platform for developers who want to create applications that give people full control of their digital selves. The platform is based on the @protocol - a network protocol for the secure exchange of information only between known entities. It uses a unique identifier called an @sign that, combined with the @platform (which is based on the @protocol), allows people the freedom to share, withhold, or retract their information at will with minimal effort, and the developer no longer has to bear the cost and risk of storing and managing people’s personal data.

@protocol :

The @protocol is the underlying network protocol used by the @platform.The @protocol’s objective is to provide end-to-end encrypted data transfer between two known @signs, but also provides access to publicly available data that is cryptographically signed by the creating @sign.

@sign

Each participant in the @protocol has a unique identifier known as an @sign. @sign’s are centrally registered and the rest of the infrastructure is fully distributed.Every @sign has a unique secondary server microservice that is accessible on the Internet via a unique Fully Qualified Domain Name (FQDN) and TCP/IP port number and Secure Sockets Layer (SSL) certificate.

root server :

The root servers are the only centralized part of the @protocol and are centralized to provide a single namespace and a globally dependable platform. No data beyond the @sign and responding authoritative secondary server is held on the root servers. This information is considered public, and no authentication is required to look up the secondary server for a particular @sign.

secondary server :

Secondary servers provide the second tier of the @protocol architecture, and are responsible for answering lookups for specific @signs. Secondary servers are generally deployed as microservices running on orchestrators such as Docker Swarm or Kubernetes, but can also run as standalone executables. Secondary servers have to be uniquely Internet addressable through use of an FQDN & Port pair that can be translated via DNS to a unique IP & Port.

Argel Bejarano

Hermosillo, Mexico
Argel is a software engineer with over 10 years of experience. As a Google Developer Expert for Flutter and Dart, he has become a distinguished speaker, writer, and organizer in the Spanish developer communities, with over 30K members in the Flutter & Dart Spanish Community he founded. When he is not on the computer hacking away, Argel is a father, sportsman, and Brazilian Jiu-jitsu practitioner. Argel contributes extensively to the @platform repository and helps grow the presence of the @platform in the Flutter community.

Majid Hajian

Oslo, Norway
Majid is a Google developer expert and passionate software developer with years of developing and architecting complex web and mobile applications through Flutter, Dart, PWA. He has become a noteworthy presence in the Flutter community by speaking at events, contributing to open source, and organizing meetups and conferences. He’s an award-winning author of Progressive Web Apps and Instructor at Pluralsight. With Majid's advice, we've built our community of developers and hosted global events to spread awareness of The @ Company’s technology.

Simon Lightfoot

London, United Kingdom
It is impossible to talk about the Flutter Community without mentioning Simon. His first encounter with Flutter was in October 2017, and the technology left such an impression on him that he has been working exclusively in Flutter ever since. Today, Simon is the co-founder of various communities such as Flutter Study Group and Flutter Dev Community. His efforts have made him one of the most prominent tech figures in the world of Flutter. He works with the core team at The @ Company on developer experience and community building.

7.5 - @platform whitepapers

The whitepapers will help you get a deeper understanding of our technology

7.5.1 - The @platform

This whitepaper will help you get a deeper understanding of the @platform

Author(s)@barbara,@colin,@kevin & @ethnic28
DateJuly 21, 2021

Executive Overview

End-to-end encrypted everything

There is growing demand for real solutions that address the privacy concerns of consumers globally. The rise in popularity of applications with features like end-to-end encryption is but one example. But such solutions are difficult to build, expensive to operate and often insufficient in the degree that they actually deliver privacy.

The current status quo, in which businesses collect and consolidate consumer data, results in large databases that are tempting targets for hackers. Because of this, new privacy laws such as the GDPR, CCPA, and 17 US state legislations are being implemented. Compliance with these laws is a challenge developers face today that is often treated as an afterthought,and we believe that a better approach is to use a platform that delivers “privacy by design” and assures compliance from the outset.

Thus we have created a new architecture that addresses these issues at a fundamental level, starting with a new network protocol and a modern development platform implementation that makes it easy for developers to deliver “privacy first” applications.

If you are thinking about how to deliver applications that are end-to-end encrypted, surveillance-free, and resistant to malicious hacking, read on. The @platform is designed to make it easy to do just that.

A Simple Definition of the @platform

@platform definition


Figure 1. A Simple Definition of the @platform

The @ Company has created an open platform for developers who want to create applications that give people full control of their digital selves. The platform is based on the @protocol - a network protocol for the secure exchange of information only between known entities. It uses a unique identifier called an @sign that, combined with the @platform (which is based on the @protocol), allows people the freedom to share, withhold, or retract their information at will with minimal effort, and the developer no longer has to bear the cost and risk of storing and managing people’s personal data.

Technology Overview

This document describes a software platform with the necessary technology and tools to help developers create beautiful privacy-first mobile applications that are end-to-end encrypted, surveillance-free, and resistant to malicious hacking.

It is called the @platform, and is an open source project intended to make it easy for developers to develop and deploy just such applications including the requisite supporting infrastructure at no cost.

The @platform open source project is embodied in a public repository which includes a full stack reference implementation, SDKs for application developers, useful documentation, tools, samples, and examples.

The reference implementation is licensed under the BSD 3-Clause “New” or “Revised” License. At the time of writing, a version written in the Dart language that supports the Flutter cross-platform framework has been released, with other languages and framework support expected in the future.

The technology is distributed via the Pub package manager as libraries for application developers, and via dockerhub as containers for developers' infrastructure components.

From the Perspective of an Application Developer

The Beautiful Thing About a Protocol

There are many important and unique things that arise as a result of an architecture based on a protocol. There is ample precedence for this statement based on other successful examples (SMTP and TCP/IP come to mind). The most important things for an application developer to know about how to use the @platform are:

  • Data and processing are pushed to the edge of the internet.
  • Applications are based on a peer-to-peer shared data model.
  • The sharing of access to private data between application instances is end-to-end encrypted only between provable known parties to prevent surveillance, leakage, or other hijacking attacks.

These things are the result of the use of the @protocol and can seem very different from the traditional client-server or API means of sharing access to data. Thus, the mental model for such a system, especially from an application developer’s perspective, is worthy of discussion up front.

Data shared on a device
Figure 2: Example of How to Store Shared Data on a Device

As shown above, an application developer need only use the platform SDKS to store the application data locally on the device and include an @sign to share it with; the @platform will ensure that the data gets routed to the intended destination in a safe and secure manner. This peer-to-peer model is in contrast to centralized data stores that are fraught with risk of intentional or accidental breach or exposure of private data.

A Different Way of Thinking About Data

Certainly, there are many benefits to a decentralized data model with strict control on the part of the owner, and the @platform ensures that sharing access to private data is end-to-end encrypted, surveillance free and resistant to malicious hacking. But, there are other benefits of this architecture that may not be so obvious.

People Own Their Data

While this is obvious for a “privacy by design” platform, there are additional features that arise from adherence to this principle.

  • Data can be portable between similar applications (i.e. swap one Calendar app for another without losing your data), which gives people more choices.
  • Application’s data can be shared between disparate applications (e.g. Contacts. Events, Messages) to create altogether new user experiences.
  • Applications can reason over “all” their data to produce compelling new services, perhaps aided by ML algorithms (with inferences executed on the mobile device in order to preserve privacy).

End-to-End Encryption

The @platform ensures that the owner of their data has complete control over it. This is a result of three basic things (though there are many more additional options available that are explained below):

  1. Encryption happens at the edge.
  2. The encryption keys are only available at the edge.
  3. Data sharing is uniquely encrypted between the owner and the intended recipient.

Data on The Edge

A person’s private data is only available “in the clear” on either the owner’s device since only they have the keys to decrypt it or from cached data that can only be decrypted on the device of the recipient it was shared with. This removes the centralized target for hackers and makes any attempt at a large-scale data breach impractical.

P2P (peer-to-peer, person-to-person)

Also important to note is the fact that centralized, shared-tenant resources are no longer required for the sharing of access to private data. This not only saves cost, it also increases performance and security from things like denial of service attacks.

A Kind of Polymorphism

This means of end-to-end encryption of data has a very interesting side effect in that it produces a kind of polymorphism. Since the shared data is end-to-end encrypted uniquely peer-to-peer between two parties, the answer to a query depends on who is asking, and a different response may be returned for different parties for the same query. For example:

QueryWho’s askingResponse
location@aliceanonymous<public>California
@bobBay Area
@carolHome <address>

This has already been used to create some very interesting new UX (User Experience) designs and offers many other potential use cases.

Conceptual Model
Figure 3: Data Model Includes Owner Data and Cached Data from Others

Enforcing data ownership is another important concept as illustrated in Figure 3. In this system, application data becomes a combination of data created by one @sign combined with data that has been shared by others. Since the shared data is encrypted uniquely for the intended recipient, it can only be accessed by them. In addition, the owner maintains control of it (i.e. updates and deletes), though it may be cached for offline use. This means the owner can literally delete their information from another person’s phone.

The @platform Architecture (Under the Covers)

For those who are interested in the nitty-gritty details, this section covers many of the architecture and design details that have been used for the development of this project.

Functional Goals

  • Provably true privacy and security.
  • Support for all popular device architectures with native levels of performance.
  • Robust, resilient, and scalable to internet levels.

Technical Goals

  • Dependable - designed for global scale (~100 billion people, entities, or things).
  • Extensible - the platform is simple and extensible.
  • Near real time - data currency ensured.
  • Online/offline use is supported.

Architectural Guidelines

  • Modular, componentized design for flexibility and extensibility.

Design Patterns And Methodologies

Separation of Concerns

Great care has been taken when designing this architecture to apply the principles of “Separation of Concerns”. The result is a modular design that is easy to understand and maintain.

Verbs and Verb Executors

While the SDK makes it simple and intuitive for developers to manage their data interactions, under the covers are the important use of protocol verbs. In order to ensure that verbs are handled in a consistent manner, the use of a “verb executor” repeatable pattern has been used.

Use of Factory Classes

Across the entire project, you will find the use of factory classes to encourage ​​easy to implement, change, test, and reusable code.

Interfaces and Implementation Classes

For the areas of software that represent modules that other developers may want to implement some other way, we have also created interface and implementation classes as a good practice of modular design.

Sequence Diagrams for the Important Flows on the Server

@platform definition
Figure 4: Server Initialization Flow
@platform definition
Figure 5: Connection Request Flow
@platform definition
Figure 6: Wiring of a few Important Classes
@platform definition
Figure 7: Verb Execution Flow

About Dart & Flutter

Dart is an object-oriented, class-based, garbage-collected language with C-style syntax. We selected it for our reference implementation for the following reasons:

  • Dart is type-safe with both AOT and JIT compilers that are quick and reliable.
  • Dart can compile to native code for most common HW+OS architectures.
  • Flutter delivers near-native performance (approximately two times faster than JavaScript).
  • Dart enforces object-oriented programming.
  • Both Dart and Flutter have large open source ecosystems of contributors with many value-adding libraries released and many more being developed.
  • The Pub package manager makes adoption and distribution of Dart and Flutter libraries simple.

@platform definition

Figure 8: Functional Architecture

Application Level Components (Starting at the Top)

One of the most compelling things about Flutter is the ability to easily integrate and manage application components (called widgets) written by others into your code. Not only does the @platform take advantage of this, it also includes a number of widgets that make it easy to develop an application, access data or take advantage of services that are provided by the platform

Widgets (at_widgets)

The @platform currently includes the following list of widgets that are available on pub.dev as packages with the source code available on GitHub as well.

at_onboarding_flutter

A Flutter plugin project for onboarding any @sign in @platform apps with ease. Provides a QRscanner option and an upload key file option to authenticate.

at_chat_flutter

A Flutter plugin project to provide a chat feature between @signs built on the @platform to any Flutter application.

at_common_flutter

A Flutter package to provide common widgets used by other @platform Flutter packages.

at_backupkey_flutter

A Flutter plugin project for saving the backup key of any @sign that is being onboarded with @platform apps. The backup key can be used to authenticate in other @platform apps.

at_contacts_flutter

A Flutter plugin project to provide ease of managing contacts for an @sign using @platform.

At_contacts_group_flutter

A Flutter plugin project to provide group functionality with contacts using @platform.

at_location_flutter

A Flutter plugin project to share locations between two @signs and track them on OSM (OpenStreetMap).

at_events_flutter

A Flutter plugin project to manage events (time, place and attendees) using the @platform.

at_follows_flutter

A Flutter plugin project that provides a basic social “follows” functionality for any @sign. Provides a list of @asigns that follow you (followers) as well as the @signs that you follow (following) with the option to unfollow them.

Libraries (at_libraries)

In addition to the Flutter widgets listed above, there are a number of Dart libraries that provide useful functionality that can be used with the @platform as well.

at_persistence_spec

A Dart library containing abstract classes that defines what an implementation of the persistence layer is responsible for. This can be used to guide implementation of other persistence solutions for servers or SDKs as desired.

at_commons

A library of Dart and Flutter utility classes that are used across other components of the @platform.

at_client

A Dart library with the core, non-platform specific abstract and implementation classes that define what an atClient SDK responsibilities are.

at_client_mobile

A Flutter extension to the at_client library which adds support for mobile, desktop and IoT devices.

at_lookup

A Dart library that contains the core commands that can be used with a secondary server (scan, update, lookup, llookup, plookup, etc.). This library is also used for building command line tools.

at_persistence_secondary_server

A Dart library with the implementation classes for the persistence layer of the secondary server.

at_server_status

A Dart library that provides a means to check on the status of the @root server as well as the secondary server for any particular @sign.

at_utils

A Dart library that contains various utility classes such as atSign, atmetadata, configuration, and logger.

at_demo_data

A Dart library that contains test data, testable @sign credentials and demo environment variables that can be used for writing demo apps and testing with the local test environment.

at_utf7

A Dart library that provides methods to encode/decode strings to/from the UTF-7 format as defined in RFC 2152.

at_contact

A Dart library for managing contact data that developers can use for their applications.

at_base2e15

A Dart library for encoding binary data as text using a unicode string format for increased efficiency as compared to Base64 encoding. Each unicode character represents 15 bits of binary data.

at_server_spec

A Dart library containing abstract classes that defines what implementations of the root and secondary servers are responsible for.

The @protocol Verb Tree

Before we look at some of the sample code, the verb tree gives you the big picture of all of the verbs and what can be executed with the @protocol. Following this is the @platform implementation that most developers will use to develop their applications.

@platform definition

Figure 9: The @protocol verb tree

It is worth noting that the @protocol verbs are involved in the secure exchange of information, either public or private only between two known parties. This requires such things as E2E encryption, key management, and passwordless, zero trust authentication. The SDKs are designed to take care of this complexity for the developer with the goal of making such security ubiquitous.

The AtClientSDK (at_client_sdk)

The AtClientSDK encapsulates the @protocol verbs and provides an application level abstraction that is familiar to developers.

Setup and Configuration Methods

The AtClientSDK requires initialization and setup. For convenience, there is a preference object with default settings that is used to configure the instance.

<setPreferences>

void setPreferences(AtClientPreference preference)

The setPreferences method sets the preferences such as sync strategy, storage path etc., for the AtClient instance.

<createClient>

Future<void> createClient(String currentAtSign, String? Namespace, AtClientPreference preference)

The createClient method is used to initialize the AtClient instance. This method accepts an @sign, non null application namespace and an AtClientPreference.

<getClient>

Future<AtClient?> getClient(String? currentAtSign)

Returns a new AtClient instance. This method requires a non null @sign.

Sync Verb Methods

The AtClientPreference model includes a parameter for how the application will handle synchronization of data to the secondary server. These can be set to one of three enumerated values.

<SyncStrategy.IMMEDIATE>

SyncStrategy.IMMEDIATE will synchronize changes to local keys immediately as they change to the secondary server for update and delete commands.

<SyncStrategy.ONDEMAND>

SyncStrategy.ONDEMAND will synchronize changes only when SyncManager.sync is invoked.

<SyncStrategy.SCHEDULED>

SyncStrategy.SCHEDULED will synchronize changes periodically once every time interval specified by AtClientPreference.syncIntervalMins has elapsed.

Scan Verb Methods

The scan verb is used to retrieve all the available keys that are either public or have been specifically shared with some @sign that has been authenticated. This has been abstracted in the getAtKeys method of the AtClientSDK so as to be more familiar to application developers

<getAtKeys>

Future<List<AtKey» getAtKeys({String? regex, String? sharedBy, String? sharedWith});

The getAtKeys method is used to execute the scan verb and retrieve a list of all the relevant keys from a secondary server. These can be filtered by applying a regular expression [regex], by specifying the “sharedBy” or “sharedWith” @signs.

Update Verb Methods

The update verb is used to write entries in the secondary server as key/value pairs. This has been abstracted in the put method of the AtClientSDK so as to be more familiar to application developers.

<put>** **

Future<bool> put(AtKey key, dynamic value, {bool isDedicated = false});

The put method in the AtClientSDK is used to write data into a secondary server as a key/value pair. The @sign must be authenticated to run this method.

<putMeta>

Future<bool> putMeta(AtKey key);

The putMeta method in the AtClientSDK is used to write metadata values for some key/value pair data on a secondary server without needing to update the value. This is done to increase efficiency. The @sign must be authenticated to run this method.

Lookup Verb(s) Methods

The lookup verbs are used to read a value from a secondary server using a key. There are several variations of the protocol verb that the SDK uses to retrieve:

  • lookup

    The lookup verb is used to lookup a value on a secondary server for another @sign’s secondary server.

  • plookup

    The plookup verb is used to lookup a public value from another @sign’s secondary server if the client is authenticated. The plookup verb can only be executed on a remote secondary server.

  • llookup

    The llookup verb is used to lookup a value on the local secondary server of the current @sign.

These have been abstracted in the get and getMeta methods in the AtClientSDK so as to be more familiar to application developers

<get>

Future<AtValue> get(AtKey key, {bool isDedicated = false});

The get method in the AtClientSDK is used to read the value of some key. It first attempts to read from the local persistence store, then from a remote cloud secondary server.

<getMeta>

Future<Metadata?> getMeta(AtKey key);

The getMeta method in the AtClientSDK is used to read the metadata of some key that has been created automatically and contains useful information about the data, such as who it was created by, when it was created or updated, the current version, etc. It first attempts to read from the local persistence store, then from a remote cloud secondary server if not found.

Delete Verb Methods

The delete verb is used for deleting key/value pair data on a secondary server. The AtClientSDK also uses the term delete for its method as well.

<delete>

Future<bool> delete(AtKey key, {bool isDedicated = false});

The delete method in the AtClientSDK is used to delete the key and value from @sign’s local persistence and then syncs the deletion to the cloud secondary server according to the AtClient’s sync preference (e.g. immediate).

Event Verb(s) Methods

In order to efficiently ensure data gets communicated between secondary servers, there are two verbs that are used to manage the propagation of data events.

  • monitor

    The monitor verb is used to stream incoming notifications from the secondary server to @Client.

  • notify

    The notify verb is used to notify another secondary server of an update or delete to some key/value pair.

<startMonitor>

Future<void> startMonitor(String privateKey, Function? notificationCallback, {String? regex});

The startMonitor method in the AtClientSDK is used to create a persistent connection to a secondary server to receive notifications. Whenever a notification is created on the server, the monitor calls the specified notification’s notificationCallback function. Optionally, a regular expression can be passed to filter the notifications.

<notify>

Future<bool> notify(AtKey key, String value, OperationEnum operation,

_ {MessageTypeEnum? messageType,_

_ PriorityEnum? priority,_

_ StrategyEnum? strategy,_

_ int? latestN,_

_ String? notifier,_

_ bool isDedicated = false});_

The notify method in the AtClientSDK is used to propagate a change in the value for some key [AtKey] to the secondary server for the [sharedWith] @sign. Optionally, an operation can be specified and the data value and metadata can be sent along with the key as part of the notification. For rapidly changing data, the [isDedicated] parameter can be set to true to create a dedicated connection to the other secondary server.

<notifyAll>

Future<String> notifyAll(AtKey atKey, String value, OperationEnum operation);

The notifyAll method in the AtClientSDK is used to propagate a change in the value for some key [AtKey] to a list of [sharedWith] @signs. Optionally, an operation can be specified and the data value and metadata can be sent along with the key as part of the notification.

<notifyList>

Future<String> notifyList({String? fromDate, String? toDate, String? regex});

The notifyList method in the AtClientSDK returns the list of received notifications of an @sign. Optionally, notifications can be filtered by from date, to date, and regular expression.

<notifyStatus>

Future<String> notifyStatus(String notificationId);

The notifyStatus method in the AtClientSDK is used to check the status of a notification based on a notificationId.

Stream Verb Methods

The @platform supports streaming connections in addition to asynchronous connections. The stream verb is used to create a direct connection between two AtClient instances that are joined together on the originator’s secondary server that can be used to send an encrypted stream between two devices with @signs.

<stream>

Future<AtStreamResponse> stream(String sharedWith, String filePath, {String namespace});

The stream method in the AtClientSDK creates a persistent connection for encrypting and sending a file from a device [filePath] to a [sharedWith] @sign.

File Sharing Methods

The @platform also includes a “store and forward” means of securely encrypting and sharing binary data (files) using a filebin2 service as a temporary storage mechanism.

<uploadFile>

Future<Map<String, FileTransferObject» uploadFile(List<File> files, List<String> sharedWithAtSigns);

The uploadFile method in the AtClientSDK can be used to upload a list of files to a filebin for temporary storage and then shares the file download url with [sharedWithAtSigns]. The method returns a map containing each sharedWithAtSign as the key(s) and [FileTransferObject] as the value(s) which contains the information required to download and decrypt the file.

<downloadFile>

Future<List<File» downloadFile(String transferId, String sharedByAtSign, {String? downloadPath});

The downloadFile method in the AtClientSDK can be used to download a list of files for a given [transferId] that has been shared by [sharedByAtSign]. Optionally, you can include a [downloadPath] to download the files.

Config Verb Method

The config verb is used to configure block list entries in the secondary server. If an @sign is added to the block list, then connections to the secondary server will not be accepted.

Verb Parameter Reference

required* optional’

VerbParameters
fromatSign* - @sign you claim to be
cramdigest* - SHA512 digest
pkamsignature* - Signed challenge
polNA
scanforAtSign - Scans the keys shared by forAtSign

regex - Regex to which the @addresses has to be matched to be returned as a result

updatettl -Time to live in milliseconds. Value for the key won't be available after the ttl’

ttb - Time to birth in milliseconds. Value for the key will be available after the ttb’

scope- Public vs Private

forAtSign* - For whom the value is being set

atKey* - Name of the @address

value* - Value for the @address

lookupatKey* - Name of the @address

atSign* - an @sign’s namespace

llookupatKey* - Name of the @address

atSign* - an @sign’s namespace

plookupatKey* - Name of the @address

atSign* - an @sign’s namespace

deleteatKey* - Name of the @address
statsstatId - Ids of the statistics to display
configwhatToConfig* - Thing to configure

configValue* - Value of the thing to configure

notifyforAtSign* - the @sign’s to notify

key* - Key to which the change has happened

change* - Change itself

monitorregex - Regex that needs to be matched for the value to be monitored

Service Level Components

Root Server (at_root)

The root server is responsible for storing and retrieving the addressable location of an @sign’s secondary server. The architecture is highly distributed and horizontally scalable to internet levels (~50BN endpoints). The information it contains is public and it contains no personal information whatsoever.

Secondary Server (at_secondary)

The secondary server is an internet accessible microservice that is responsible for orchestrating the secure exchange of information between @signs and synchronizing data between the AtClient instances on an @sign owner’s various devices.

It is important to note that private data stored on a secondary server contains only data that has been encrypted on the data owner’s device and the keys are only accessible on that device. As a result, it is “provably true” that nobody else, including us, has access to private data.

Containers

Docker is used as a standard container format and public images are published on the Docker Hub service for finding and sharing container images.

Container Management and Orchestration

Any container orchestration system can be used as long as it can use the Docker container standard. Both Docker Swarm and Kubernetes are used by The @ Company.

Privacy and Security

Since the architecture is one of the best “privacy by design” implementations around, people by virtue of the implementation itself have complete control of their data which is encrypted both in use and at rest. As the operator of some of the infrastructure that is deployed, we use best practices to ensure that the infrastructure is reliable and resilient to prevent denial of service attacks.

Supported Platforms

Dart, the underlying programming language that the @platform is coded in, can be compiled into native binaries for ARM32, ARM64, and AMD64 on Windows, OSX, and Linux operating systems and with the use of the Flutter framework, IOS and Android.

Dart can also be compiled to JavaScript Web but with some limitations.

@platform definition

Figure 10: (Diagram from Dart overview)

Summary

This white paper has outlined the intent, architecture and implementation of the @platform that developers can use to create “privacy first” applications with advanced security features built into every exchange of data.

Our intention is that this will herald a new generation of applications that are end-to-end encrypted, surveillance-free, and resistant to malicious hacking. Please join our rapidly growing community and build something, contribute to the open source project, or just give us your feedback.

This is important for all of us.

7.5.2 - The @protocol

This whitepaper will help you get a deeper understanding of the @protocol

Author(s)@barbara,@colin & @kevin
DateJuly 21, 2021

Executive Overview

The @protocol is the underlying network protocol used by the @platform. The @platform provides people, entities, and things with unique identifiers called @signs.

Each @sign creates its own public and private cryptographic key pair. The private keys are kept private and public keys made available globally through the @protocol.

The @protocol provides verbs for updating and the lookup of fully qualified @signs like location@alice.

The @protocol supports both a public lookup, in which the querier of the data does not have to prove who they are, and a private lookup, which confirms the @sign of the entity asking for information and allows the owner of the data to decide what information to share. This means that it is possible to receive different answers for the same query if the requesting @signs are different.

For example, suppose @alice sets the public lookup of location@alice to NYC and the private lookup to her physical address. If anyone looks up location@alice without proving who they are, they will receive the response:

“NYC”

However, if @bob, her friend’s @sign, looks up location@alice, then the response will be:

“Conservatory Water at East 74th Street New York, NY”

The response to a query is completely under the control of the @sign’s owner, which allows for fine- or coarse-grained customization of responses. The responses also include metadata that specify how long @bob can keep the data, or how often it should be refreshed.

The @protocol also provides mechanisms for near real-time notifications that are not dependent on the services from the underlying operating system.

Technology Overview

Each participant in the @protocol has a unique identifier known as an @sign. @sign’s are centrally registered and the rest of the infrastructure is fully distributed.

Every @sign has a unique secondary server microservice that is accessible on the Internet via a unique Fully Qualified Domain Name (FQDN) and TCP/IP port number and Secure Sockets Layer (SSL) certificate.

The @protocol’s objective is to provide end-to-end encrypted data transfer between two known @signs, but also provides access to publicly available data that is cryptographically signed by the creating @sign.

The @protocol defines a set of verbs that provide proof of the authenticity of the @signs used and allows sharing of access to end-to-end encrypted data. Data ownership is held by the creating @sign and can be updated or rescinded at any time.

The @protocol uses Transport Layer Security (TLS) over Transmission Control Protocol/Internet Protocol (TCP/IP). TLS is used to provide the first layer of authentication, using SSL client certificates as well as in-flight encryption of network traffic.

The @Protocol Design and Implementation

Functional Goals

  • Easy to understand
  • Intuitive to use
  • Privacy by design

Technical Goals

  • Dependable - Designed for global scale for at least 100 billion people, entities, and things
  • Extensible - Protocol is simple enough for developers to build on it
  • Near real-time - Data currency ensured

Architectural guidelines

  • Distribute what you can, centralize what you must
  • Always ask for permission
  • Data is owned by the individual, persons, entities, or things

@sign characters

The @sign namespace, unlike DNS, extends to Unicode (specifically UTF-8), which allows characters beyond the Latin script. Emojis and other Unicode character sets are allowed thus expanding the namespace1.

There are however some rules when choosing a fully qualified @sign, like location@alice, it cannot include UTF-8 white space ,invisible characters, or control characters. @signs are also Latin case insensitive ensuring that @alice and @Alice refer to the same @sign.

Following conventions set out in DNS and the URI internet RFCs, the following characters are reserved and cannot be used as part of an @sign.

!*'();:@&=+$,/?#[]{}

@sign namespace

Whilst the @protocol itself has no real limits on the namespace being used, the @sign namespace has been constrained because of reasonable limits for the underlying keypair databases used in the clients of the @protocol. If needed in the future, this can be opened up further with no changes needed to the protocol, but it will need changes to client databases.

In the persistence layer, UTF-8 characters in the namespace are translated to UTF-7 and the UTF-7 namespace is used to store data in key/value databases.

Whilst the wire protocol uses UTF-8, the fully qualified @signs are translated to UTF-7 and need to fit in the namespace below.

The @sign itself is unique, so it’s also usable as a unique identifier for the application namespace that makes up a composite key. For example, if an application was called @buzz then to ensure the application has no namespace clash, the application owner should own the @buzz @sign. In effect, if you own the @alice you also own alice@ in the namespace for every @sign.

@protocol namespace

While this may look limiting at first glance, the namespace is actually immense.

Conceptual Architecture

Being dependable at scale is the biggest challenge to building new infrastructure at Internet scale. The other part of being dependable are the three security guidelines of confidentiality, integrity, and availability.

The architecture has to be simple to understand and the codebase must be tightly written. This allows it to be code reviewed and security tested extensively.

Two Tiers

The @protocol has two tiers of servers: the root servers, which provide a global centralized namespace, and the distributed secondary servers, which provide an always-on cache for the data owned by an @sign.

The root servers are the only centralized part of the @protocol and are centralized to provide a single namespace and a globally dependable platform. No data beyond the @sign and responding authoritative secondary server is held on the root servers. This information is considered public, and no authentication is required to look up the secondary server for a particular @sign.

Secondary servers provide the second tier of the @protocol architecture, and are responsible for answering lookups for specific @signs. Secondary servers are generally deployed as microservices running on orchestrators such as Docker Swarm or Kubernetes, but can also run as standalone executables. Secondary servers have to be uniquely Internet addressable through use of an FQDN & Port pair that can be translated via DNS to a unique IP & Port.

@protocol conceptual architecture

It is important to note that devices and clients do not have to be addressable on the Internet, as the secondary server becomes the Internet point of presence for the @sign it serves. This means that devices can be behind firewalls or Network Address Translation (NAT) and still have full @protocol functionality.

All components of the architecture speak the @protocol and the @protocol itself leverages existing protocols such as TCP/IP, DNS, and TLS. All network traffic is encrypted and authenticated with RSA public/private key pairs that are generated on edge devices.

@protocol cloud setup

All @protocol components are peers within the protocol but only secondary servers can connect and authenticate with each other.

Public Lookup

@protocol data flow

When a public lookup of an @sign is performed, no authentication is required. Any information can be made public, however, in most cases the information will be private and require the requesting @sign to prove they are who they say they are. This also prevents the root administrators from knowing who is looking up any @sign apart from the IP used to connect and the @sign being queried.

The proof is the ability to place a cookie at a specified place in the @sign’s name space. For this, the requesting @sign has to authenticate to the secondary server serving the requester’s @sign so the requesting @sign can perform the placement of a challenge. The challenge is to place a specific value in a specific location determined by the serving secondary server. Once the challenge is completed, the resolver will tell the secondary server it’s ready for the lookup of the challenge. If that lookup is successful, then the resolver has successfully proved that they are who they say they are. At that point data lookups can be requested as the requesting, verified @sign.

Private Lookup

@protocol namespace

Although the diagram looks complicated, the process is a simple series of four verbs that are used in the TCP connections between the secondary servers and the resolver code. The resolver code can live as a single executable (at_cli) onLinux/OSX/Windows, as a library or daemon, or as an app on mobile platforms such as iOS or Android.

The secondary servers can run virtually anywhere, from a cloud server to dedicated hardware or even running directly on Internet of Things (IoT) devices or mobile phones.

The only requirement is that the IP address of the FQDN and the port number given by the root server is an internet routable address and port. The resolver, in some implementations, can use the secondary server for resolving if it itself does not have full internet access. This enables the resolver to be on a private network but still be able to resolve information. Again, this is similar to the way DNS resolvers can point to another DNS server for resolution.

Root Servers and Considerations for Technologists

The @protocol pulls some of its high level architecture from DNS a design that has stood the test of time. As with DNS, the @protocol has root servers that provide redirection to the secondary server for a particular @sign. Unlike DNS there are no top level domains (TLDs) or subdomains. Data for any @sign is served only by the @sign’s secondary server but to find that server, the root servers must first be queried. This information is considered public.

The root servers have been designed to scale to billions of @signs and handle the requests for @sign lookups at near real-time, globally. To achieve this, in-memory databases are utilized and only the absolute minimum of data is stored. Just two things can be determined by communicating with the root server: does the @sign exist, and if it does, how to reach it.

The root servers’ sole role is to centralize the namespace and offer the root service dependably. When asking a root server for the lookup of a particular @sign, the root server will respond with a null if the name does not exist and if the name does exist, the FQDN of the secondary server and the IP port number for that @sign.

The format is <FQDN>:<PORT>.

The IP addresses of the root servers are held in DNS at root.atsign.org and the root server itself runs on port 64 (which happens to be ASCII for @). Connecting to the root server provides just an @ prompt and sending a name followed by a CR will return the <FQDN>:<port>. The command to exit is @exit, and any future verbs will start with the @, but at present the only verb for the root server is @exit.

Root Infrastructure

The root server is not a single machine, or even a single anything. The root service is run as a set of microservices and backended by in-memory read-only databases across multiple datacenters.

Root Server Verbs

The root server only has one verb @exit, all other inputs are considered to be lookup requests.

(Commands entered are bolded).

cconstab@cally:~$ openssl s_client -ign_eof -brief root.atsign.org:64
CONNECTION ESTABLISHED
Protocol version: TLSv1.2
Ciphersuite: ECDHE-RSA-AES256-GCM-SHA384
Peer certificate: CN = root.atsign.org
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Supported Elliptic Curve Point Formats: uncompressed
Server Temp Key: X25519, 253 bits
@spiderdeveloped
98545c6e-4ba2-52e0-9abc-6df80621ea3d.hornet.atsign.zone:2490
@isolatedcabaret
8abfc843-6407-5c92-822e-43cc1883656c.hornet.atsign.zone:2491
@realisticforeign
ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone:2489
@colouredtropical
613120ec-e54a-5c9b-9bbc-e3fd454fc93f.hornet.atsign.zone:2488
@notanatsign
null
@@exit
CONNECTION CLOSED BY SERVER
cconstab@cally:~$

Note: The @protocol uses TLS, so to connect to the secondary servers you need to speak TLS too. This is easily achieved using the OpenSSL command line tools with the arguments shown. It is important to use the “-ign_eof” option in OpenSSL to make sure your interaction is with the secondary server, not the OpenSSL command line.

Secondary Servers and Considerations for Technologists

Secondary servers provide the lookup service for a particular @sign. This forces the secondary server to not mix an @sign’s data with any other @sign’s data, unlike web servers that can provide service to multiple websites at the same time.

@ Scheme

The @protocol actually defines a secure URI (Universal Resource Identifier) for any data stored across the @protocol system (for example phone@alice) with one important difference: the value returned for an identifier is polymorphic, i.e. it depends on who is accessing the resource. In addition, the @ scheme, <atsign://>, creates a URL (Universal Resource Locator) that can be securely shared and interpreted. For example, atsign://phone@alice can be identified and used to locate phone@alice with all the security and permissions features applied to that resource. This convention is comfortable and particularly useful for storing reference values to be returned by @protocol requests.

Secondary Server Verbs

The verbs listed below will give you a high level understanding of the @protocol itself, but most of the verbs also have extensive arguments for additional functionality.

The full protocol specification can be found on GitHub.

<lookup:>

The lookup verb allows for the lookup of a particular address in the @sign’s namespace. Shown below is a connection made to the @realisticforeign’s secondary server and the lookup command is used to resolve** location.wavi@realisticforeign**. If a lookup is valid, the resulting information is returned with the data: header, newline, and a @ prompt ready for further commands.

cconstab@cally:~$ openssl s_client -ign_eof -brief ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone:2489
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@lookup:location.wavi@realisticforeign
data:{"location":"Paris france","radius":"2 mi"}
@lookup:somethingelse@realisticforeign
data:null
@^C
cconstab@cally:~$

If the lookup is not valid, then a null is returned again with the data: header, as we see above with the lookup of somethingelse@realisticforeign. The “lookup” verb used here provides public lookups. The same verb is used to resolve once authenticated as a particular @sign using the “from:” and “pol” verbs.

<from:>

The “from” verb is used to tell the secondary server what @sign you claim to be, and the secondary server will respond with a challenge. The challenge will be in the form of a full @ address and a cookie to place at that address.

There is however a check of the TLS Clients SSL certificate before the from:@sign gives the challenge. The client SSL certificate has to match the FQDN list in the root server for that @sign in either the CN or SAN fields in the certificate. If there is not a match then the secondary server will drop the connection and report the error, as seen below.

cconstab@cally:~$ openssl s_client -ign_eof -brief ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone:2489
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@from:@colin
error:AT0401-Client authentication failed : Certificate Verification Failed
@CONNECTION CLOSED BY SERVER
cconstab@cally:~$

Here we see the connection being rejected as the client either did not provide a certificate or provided an incorrect one. In effect, this means that the secondary server for @colin in the above example has to be used to connect and uses the from:@colin verb. Each secondary server has to have an SSL certificate not just to act as a server but also to act as a client to other secondary servers.

If the certificate does match then a challenge is provided, as below. Note that the “openssl” command needs to provide not only the fullchain and the key, but also the caroot file that it provides, which in this case is fullchain.pem.

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief -cert ./cert.pem -key ./privkey.pem -CAfile ./fullchain.pem   ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone:2489
depth=2 C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
verify error:num=2:unable to get issuer certificate
issuer= C = GB, ST = Greater Manchester, L = Salford, O = Comodo CA Limited, CN = AAA Certificate Services
issuer= C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
issuer= C = AT, O = ZeroSSL, CN = ZeroSSL RSA Domain Secure Site CA
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification error: unable to get issuer certificate
Server Temp Key: X25519, 253 bits
@from:@colin
data:proof:_4828b6c6-17cd-4d2e-91a3-d9eab3ebd591@colin:038d5c0e-34de-4227-9a86-da6cefe83f73
@

In this case the secondary server is asking for the challenge “038d5c0e-34de-4227-9a86-da6cefe83f73” to be placed at the location “_4828b6c6-17cd-4d2e-91a3-d9eab3ebd591@colin” with the header of “data:proof:”. The challenge being that, to actually place that cookie on the @colin, secondary server requires access to the @colin secondary server which is only achievable for the person who has the @colin keys. Once in place, the challenge response needs to be public and cryptographically signed by the @colin secondary server.

Public access is important as the @realisticforeign secondary server will want to lookup that challenge to prove the request is actually from @colin. The type of challenge and the location is in the format of a UUID v4, ensuring that the likelihood of a namespace clash is mathematically unlikely, especially when coupled with the timeout of any challenges placed within a few minutes or the fact that they are cleared once used.

It is also worth noting that locations that are prepended with _ do not show up when using the scan verb, which is explained later.

<pol>

Once the cookie is placed, the proof of life (pol) verb is used to signal to the @realisticforeign secondary server to check for the cookie on the @colin secondary server. The secondary server responds to the “pol” verb by looking up the location of the “from:” @sign using the root servers, then connecting to the secondary server for that @sign and using the “lookup” verb to look for the cookie at the challenge location. If the cookie is found then the prompt is changed to the @sign in the from:@sign, confirming that the “pol” verb was successful. If the cookie was not found for any reason, the @ prompt is returned.

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief -cert ./cert.pem -key ./privkey.pem -CAfile ./fullchain.pem   ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone:2489
depth=2 C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
verify error:num=2:unable to get issuer certificate
issuer= C = GB, ST = Greater Manchester, L = Salford, O = Comodo CA Limited, CN = AAA Certificate Services
issuer= C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
issuer= C = AT, O = ZeroSSL, CN = ZeroSSL RSA Domain Secure Site CA
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification error: unable to get issuer certificate
Server Temp Key: X25519, 253 bits
@from:@colin
data:proof:_4828b6c6-17cd-4d2e-91a3-d9eab3ebd591@colin:038d5c0e-34de-4227-9a86-da6cefe83f73
@pol
@colin@

<cram:>

To place the cookie to prove ownership and access to the from:@sign, the resolver needs to authenticate to the secondary server. The first method of authenticating is via a shared secret which is, by convention, a 512 bit random string. The same “from” verb is used to create the challenge and the secret is added to the challenge. Then a SHA512 digest is sent with the “cram:” verb to authenticate. The secondary server does the same calculation and, if it matches what was sent, the authentication is agreed and the prompt updated to the @sign of the secondary server. Once authenticated, the “update” verb can be used to place the cookie at the requested place, or any other information placed in the @signs namespace.

The use of a shared secret is only used as a bootstrap to using the “pkam:” verb, which uses public/private key authentication.

The “cram:” verb is useful to start up the secondary server with a known secret, and then to share it with the @sign owner via perhaps a QRcode to authenticate. Next, the @sign owner’s device can cut and provide pkam keys, then it can remove the shared secret.

@protocol namespace

By using this method, no data would reside on the secondary server until the pkam authentication is in place.

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief 76103630-0f85-5dec-8a91-364bf93b0e8d.hornet.atsign.zone:2499
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = 76103630-0f85-5dec-8a91-364bf93b0e8d.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@from:@tigerequivalent
data:_2ea52658-cfdf-4541-801e-8fee7633bc76@tigerequivalent:1b79a4cd-c84b-466d-927d-0824cb1fde1d
@cram:1ed369697e1f0f53be745dc02a6aa0efd390ed3dd9d500f98b23a7a9ec6e6d9eae38eae67021579592ca2a464f5cfaafc9888d3b3aac70078554f0592022197b
data:success
@tigerequivalent@

To generate the digest, the at_cram command line tool can be used in another Unix shell, then cut and pasted into the “cram: “ verb. Here we have successfully authenticated to @tigerequivalent’s secondary server.

cconstab@Liberator:$ dart at_cram.dart ./tigerequivalent
_2ea52658-cfdf-4541-801e-8fee7633bc76@tigerequivalent:1b79a4cd-c84b-466d-927d-0824cb1fde1d
1ed369697e1f0f53be745dc02a6aa0efd390ed3dd9d500f98b23a7a9ec6e6d9eae38eae67021579592ca2a464f5cfaafc9888d3b3aac70078554f0592022197b
cconstab@Liberator:$

<pkam:>

Whilst shared secrets offer solid security, the secret is shared with both the client and the secondary server, so if you do not trust the administrator of the secondary with a shared secret, you might consider this a security risk. The solution to this issue is the use of a public/private key pair. You create a cryptographic pair of keys, one that you keep for yourself (private) and the other you give to the administrator of the secondary server (public). The challenge from the “from:” verb is given in the same way but instead of using the “cram:” verb to authenticate you use the “pkam:” verb. The “pkam:” verb used to send a cryptographically signed version of the challenge, which can then be validated by the secondary server with the public key.

This allows only the holder of the private key to authenticate without any shared secrets on the secondary server. In fact, any shared secrets can and should be safely deleted using the “delete:” verb once “pkam:” has been successful.

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief 76103630-0f85-5dec-8a91-364bf93b0e8d.hornet.atsign.zone:2499
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = 76103630-0f85-5dec-8a91-364bf93b0e8d.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@from:@tigerequivalent
data:_99af7adb-3149-4ac1-bd69-518a2087b9fa@tigerequivalent:f90555dd-e704-474a-84b2-c1d27c4d7a32
@pkam:ViL6vTa+5GU/jC5L24NQnVAO/3NmnjQ+y5LQYLP+pNQg623AQ7RP//FbNgoPYDmVPtI0s692vE0cSeApRJKmCZ+N9LZL0EIekpoBjSMo67GRECwFxdw0F3EACr/0MFgXYlZ2dDzNqqqMffPPHylhepzHUi6sssljZUrZ1KZKDUWVaWeytALLf7kymDd6bZj3xdfJHvK2/A8klOlFEbtnBQz2Th6fg0aTXdXxgR7I9uS0Vbu0bUX/k/1DrdGIAftY5MCO7t0/KdB6Sngn7Pnm+P48kSrmoTcwncActiVWuSDelZoy4omNou0fthdooYGcyGMXzlscO/coj7ec8UN0CA==
data:success
@tigerequivalent@

To sign the challenge, the private key needs to be used together with the at_pkam command line tool in another shell or within an application.

cconstab@Liberator:$ dart main.dart -p ./@tigerequivalent_key.atKeys -r _99af7adb-3149-4ac1-bd69-518a2087b9fa@tigerequivalent:f90555dd-e704-474a-84b2-c1d27c4d7a32
ViL6vTa+5GU/jC5L24NQnVAO/3NmnjQ+y5LQYLP+pNQg623AQ7RP//FbNgoPYDmVPtI0s692vE0cSeApRJKmCZ+N9LZL0EIekpoBjSMo67GRECwFxdw0F3EACr/0MFgXYlZ2dDzNqqqMffPPHylhepzHUi6sssljZUrZ1KZKDUWVaWeytALLf7kymDd6bZj3xdfJHvK2/A8klOlFEbtnBQz2Th6fg0aTXdXxgR7I9uS0Vbu0bUX/k/1DrdGIAftY5MCO7t0/KdB6Sngn7Pnm+P48kSrmoTcwncActiVWuSDelZoy4omNou0fthdooYGcyGMXzlscO/coj7ec8UN0CA==

<update:>

The “update” verb is used to do just that, it allows an authenticated @sign, after using the “cram:” verb, to update the @sign’s namespace entries. The format for those entries follows the following pattern:

<public/@share with sign>:key<@sharing sign> value

Using this format, both public responses to the “lookup” verb as well as specific responses for particular authenticated users after using the “pol” verb can be set, as in this example:

update:public:email@tigerequivalent tiger@example.com

This will create a public record for email@tigerequivalent that could be resolved by using the “lookup” verb.

update:@realisticforeign:email@tigerequivalent tiger@work.example.com

This will create a record that only @realisticforeign could resolve and then only after authentication via the “pol” verb.

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief 76103630-0f85-5dec-8a91-364bf93b0e8d.hornet.atsign.zone:2499
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = 76103630-0f85-5dec-8a91-364bf93b0e8d.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@from:@tigerequivalent
data:_9d111144-0879-411a-bead-ca38c6a464be@tigerequivalent:c4631ff9-4cdc-4ff9-a274-1a19c065e452
@pkam:RZBSLlEnRweNfgDDPvclATrCkyYaX7M1lGhQsVldv3m03VfNYHl46Bu01NXdaJAd3LCYYWQbrvgkjBW/DLHAQbNr7ndwjsv69xzUZkxoldojEJ9ay2J3Z7UuYOceNjJfOqb9q5oKkFCPT0fWxmnla4sITQ3rQIFhKs+/Kk9bj5Z0KCIUV+VIQQZAayWiW7oobqocxpo9awDmwTnj68BOXey88ZqxrCp9kN5bwoa3lkb+s+q7QZNcodc1wdFR4yoK9LuyR++fdogp89y9t7bc2oofujax5pOQBn3nWqg9nYHptLyFeIBI0jBaGo6wPwtmVavj/SHSEK8KXUopPNDsAA==
data:success
@tigerequivalent@update:public:email@tigerequivalent tiger@example.com
data:18
@tigerequivalent@update:@realisticforeign:email@tigerequivalent tiger@work.example.com
data:19
@tigerequivalent@

<plookup:>

The “plookup:” verb provides a proxied public lookup for a resolver that perhaps is behind a firewall. This will allow a resolver to contact a secondary server and have the secondary server lookup public @sign’s information. This will be useful in large enterprise environments where they would want all lookups going through a single secondary server for the entity or where a single port needs to be opened through a firewall to lookup @signs.

Shown below is an example of “plookup:” showing the public value of email@tigerequivalent then the value for the same query but as @realisticforeign using the “lookup” verb.

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone:2489
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@from:@realisticforeign
data:_99230666-2590-4d2f-a68e-819add5ecad5@realisticforeign:ef4293cd-350d-431e-8c9e-24d2f78520aa
@pkam:HoHl+SDBmvLrqdyX4y0wsC1gbRVLrSVo2aKkCrLXlfyiFNIbHzFX7m+TRqonEZ+uX4c2y9A6lsk1QY9rUsTKrJWmwFfZ3fpwpKkuYEwHmlMXC7gVHMi2CbLxesYCSX7XHd8ZEHIJxDR2S200k3gGwkQHmgBwd0nXsdSQap6ZW8jmp6Fxa88qzOYMvlKX9uGmJQkQ+EPAyY+8WOETFW3hf9sQ/EI4lXfh27atrnqljqqnklvWWulFnUop0oXTeiH8vXBC6wxZ1lJNo0+6pEXmoos0rgLqcq+gbPMpxj9zl3bTCRqRTAmQ8+Wj4U3P4YlxvJuluOwjl9j2y0oHUhKLyA==
data:success
@realisticforeign@plookup:email@tigerequivalent data:tiger@example.com
@realisticforeign@lookup:email@tigerequivalent
data:tiger@work.example.com
@realisticforeign@


<scan>

The “scan” verb is used to scan the available @ addresses for you, either at the public level or once the pol process has been completed. This allows addresses to be discovered and perhaps be collected. If an address has a _ character as its first character, then it is omitted from the scan list although it can still be looked up if known. The following example shows just that.

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone:2489
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@scan
data:["location.wavi@realisticforeign","locationnickname.wavi@realisticforeign","publickey@realisticforeign","signing_publickey@realisticforeign"]
@

The “scan” verb only scans for @ addresses that are available to you at your current authentication state. If unauthenticated only public information is provided, once the “pkam”/”cram” or “pol” verb has been successfully then private to the @sign that authenticated will be visible.

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone:2489
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@scan
data:["location.wavi@realisticforeign","locationnickname.wavi@realisticforeign","publickey@realisticforeign","signing_publickey@realisticforeign"]
@from:@realisticforeign
data:_96dc3af8-1657-4fd6-86e3-53726876e87f@realisticforeign:989094d4-fa65-418a-878b-df72535adbb6
@pkam:BLweOba0B68Yx25EPoTCDFxL08HUslT3TTE51bTcMTljHRKacVPWeXaiUo8Zuvehv3XtD5eQbU3muWv1Md0xDSjIn7dnzNCYp99LW7I61cX2m3Aw48DTpH4w1xhBBGPII6riDl9eP4InIZQehMmqcpGZknTgXO+MTk8EFYwUr8s1opGCPD2DE4mGyCXAUN4lhXk1hSLoqDOUk5qWHR6sb/VO9hhlPZBoZ4hPjMaTCWxKIoGGnxdPsy4EntKURtzVXwUC7UiySy8WxVrZULTacDbFR8Y1Kbd4in4X5oZGWcLAxYlQxHEf5dpbafTUoI0MGF9wM1gSt5CLJzh/331Igw==
data:success
@realisticforeign@scan
data:["@realisticforeign:signing_privatekey@realisticforeign","cached:public:_notlisted@realisticforeign","cached:public:email@tigerequivalent","public:location.wavi@realisticforeign","public:locationnickname.wavi@realisticforeign","public:publickey@realisticforeign","public:signing_publickey@realisticforeign"]
@realisticforeign@


<llookup:>

As an authenticated user after the “cram:” verb, the “llookup:” verb can be used to locally lookup @ addresses stored on the secondary server.

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone:2489
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@scan
data:["location.wavi@realisticforeign","locationnickname.wavi@realisticforeign","publickey@realisticforeign","signing_publickey@realisticforeign","weather@realisticforeign"]
@from:@realisticforeign
data:_e8defea5-d893-4a22-851f-db249e87a485@realisticforeign:110c8842-b061-43c7-9f94-8f91fc626391
@pkam:GkzZ8/z7H8NZdPIqQAVWf/o3fG+H3KnapXlQwe1IVSBXsoqIyWugSj0odOZfFIq84ADOgZW9UDdmTOLvXXqjg4X4/WtDGZTzgMGmYl7NXNR6otkbWDoPW6e3vX/ly7tmh47MiuEQVScjgGRw0Dtum5geWjKGt1o2GVMqRWzZVF7BjUhKCwSn6vnq/ecmAy4d12W+XBV70p937EioZtUzEpn+l8p7sSWcvV5pwcWNHRCVAY1uz6DiKeik6Rc7OUJbUJSxMPhUMMwywVDitUXnO/xw6mVCYkhHrHl13kDm6jSvMSEWTKvBw6zG044ZbsN71sV+0mMvBXbfxFw2l/SX7g==
data:success
@realisticforeign@scan
data:["@realisticforeign:signing_privatekey@realisticforeign","cached:public:_notlisted@realisticforeign","cached:public:email@tigerequivalent","public:location.wavi@realisticforeign","public:locationnickname.wavi@realisticforeign","public:publickey@realisticforeign","public:signing_publickey@realisticforeign","public:weather@realisticforeign"]
@realisticforeign@llookup:public:publickey@realisticforeign
data:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjCkLI6RjrFMl3GmHoUg0DgHPa0vv4nZsWbKv8j/ae6C34Gc/dt7dC/2/bSc7TYD45QZtOPdKjCQoVAR5WbLCiWwt49Kyt0IeNT4zPftFvhYgFNIrYKPI6QMnzNJ0SKbYOnE0HhOjcIjIbMTsh4griOwYHBu/eXdcFU+DpGKbuX/mWxZqeqyNmd1vgJDQBJNaUXmzCyA7xovaJ+EnZVA3hddwUZhBkiUCm6msVj23nYNbQ+ddkS+wC1iTxVaPV13LklNkAHccCpX+Rv+hxBkus5ppa874xlKSm/+r/whG7gZ3oXgZTlrCvchmS2wStSKwupnZLBxYxZbBTyX678U5dQIDAQAB
@realisticforeign@


<delete:>

The “delete:” verb is used for just that: deleting @ addresses, but it can only be used by an authenticated user following the “cram:” verb. The “scan” verb is useful to find the correct address to delete.

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone:2489
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@from:@realisticforeign
data:_30706078-63f0-428e-98ac-a7e60b2f81b3@realisticforeign:42a9b6f3-4c74-4f0d-918d-25bc46a2b604
@pkam:BBNHiBgYervD1SbUOwHeyFl8bD802zKq+saAbhc1d4NtebqFGuYhALsjIqBWEkE5VexViN9fpG1S6ZTnrMsxzoG8abLvhk+t8SdfmoEJ/zwsbommqz3sw2UsYDJSj/qBSmuVfG86waZEEvpbL4ytNmCyqmF299eH5X/CUexHvHin3uooxYjLjbRnPo1aUj3IqIaOq4pz7T4IaEZsaiVyILgH5h8YE/JXgFo6QhnEwDWVHB3w8uB4Pb6dIJeenHV/BULrL9S6hQXKlhOiOUAQXgJGiYi3LbV4xcIy6vX6tXjtwDxAFccWiV5s5B/tezNIx3VLtBfIA4BwjJi/NjnajQ==
data:success
@realisticforeign@update:public:test@realisticforeign test data
data:13
@realisticforeign@llookup:public:test@realisticforeign
data:test data
@realisticforeign@delete:public:test@realisticforeign
data:14
@realisticforeign@llookup:public:test@realisticforeign
data:null
@realisticforeign@

<notify:> and <monitor> The notification subsystem

The @protocol also provides methods of push notifications that are independent of the operating system being used.

The “monitor:” verb is used to monitor either all or specific notification events that are sent using the “notify:” verb. Notifications are both queued and managed by the secondary server, and the status of an individual notification can also be seen.

The notification subsystem works to get the notification to the secondary server of the @sign being notified as efficiently as possible, and also handles retries in the event of things like network failures.

Sending a notification to @colin with the “notify” verb

cconstab@cally:~$ openssl s_client -brief 76103630-0f85-5dec-8a91-364bf93b0e8d.hornet.atsign.zone:2499
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = 76103630-0f85-5dec-8a91-364bf93b0e8d.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@from:@tigerequivalent
data:_4f78605b-2c35-4ed7-90f0-6e2d0f4d1637@tigerequivalent:749c97c9-a49a-4222-a205-87097f9fb325
@pkam:M+ypyQsoexpnwzisyS9M+sN9xmDHXXbzerQvV13kghthGIt/GWTnJAb+x7mbohST3NHuqn2MQw0cAe5kMXu/OmEElAxl9/kFtns4qz16d1brDejL1iJSqJETeIN6A53isoNoLsuoEnKbYA6OBeFlMFw9eqYN5HC/AQaB58BBPnlMc9dk6UpiFW0KCLymltLl9UTc5U7n0n2daDinI6LPxO/wAU5fY8+VMM8sacT9i5MZyawtZvpSjELkPVgM+/iUY/e6EIHvuafcoMqrtaZMHNbp9M6B3WI6210pWECusUbTl00sHoCvMt4hybxuqf7gucLjBu0f9uY2BloLIhzrpw==
data:success
@tigerequivalent@notify:notifier:system:@colin:location.wavi@tigerequivalent
data:680b8352-42c0-4e0b-a0bf-5b551c78512d
@tigerequivalent@

The “monitor” verb allows a client device to monitor notifications in near real-time. Notifications are sent to all sessions running the “monitor” verb.

Receiving a notification on @colin with the “monitor” verb.

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief 79b6d83f-5026-5fda-8299-5a0704bd2416.hornet.atsign.zone:1029
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = 79b6d83f-5026-5fda-8299-5a0704bd2416.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@from:@colin
data:_a101b1e1-7682-47ea-8524-9807511cfa11@colin:b75d1f96-d24a-4a4b-a263-9e82db64804e
@pkam:eXSq+1TM30hecmqyw+xKrZOF0Q5I+zgSc98Lsr5fSB5HQtxGS00aYsdvg4IaI2RvcsJIg7KJIF0PtOfGnxN7Qq+xgsZGKN+0BN4xUcpa++H8MDpw2HXRmrzN18fRA1JmJzwdzJN95rgMHrq2OC+avt+gx3GoSPpkwXQLXvjcXoRwD/4/sJ8npKx6ONYU2AN+tXjhlJQl/vrl1dKaFFt0mgsijW8S8m0JC9EiSQsLKRXDNV0Kcux61QJ+5YVvFtbIplsH12sPTrLJjk9oWxE+RYSStSg20nP/X7q6OsmblBhojVH38YDx0dLyswLovjcOPiRGNn/LcCU7EKZGc5VRfw==
data:success
@colin@monitor
notification: {"id":"f8c8a763-d9f4-4660-8595-5bafa9ea06b4","from":"@tigerequivalent","to":"@colin","key":"@colin:location.wavi@tigerequivalent","value":null,"operation":"null","epochMillis":1626462703744}

<stats:>

The “stats<:>” verb provides an authenticated @sign with a number of stats.They can be listed with stats and detailed individually with “stats:<number>.”

cconstab@cally:~/@colin$ openssl s_client -ign_eof -brief ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone:2489
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = ba46657d-227b-5ecf-ad16-161f80249772.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@from:realisticforeign
data:_a3ac3fd9-d57e-4f7e-92f4-1bfebc1d5a8f@realisticforeign:11aebdd6-b0f7-44f0-8f9e-961546f70952
@pkam:D2kdNJ9yzdpU6EZlbbcgv8DkzG/+g7/ecjkba5DVoCyK2lRGZDabnAM5D/ik+cbmm1Ix1fonHCNcCXHhfVLqFOjVC2lEu//oH7Hean3dmTtfva1jxuyAQcia0VWQWC0u4EFZeeVqREK7TChctB2VXOw4VBcHlS9ub2UumD9EEzzfsIFbmuUkJa8NemVHWwgBdhym1c2XFOB/x91WUORmFLBdX9QNCWp6L1tuQHEmdSOsQLu2nc8Fg0CtIC8Z8uQf8wHmHRAyOHhZq87b8hrVXYnMUdc+TWEC+w/NeENKHOmS/nhpXZEHXAMTCLY+iki7uHuqhZyvePaLzklt2whoEg==
data:success
@realisticforeign@stats:1
data: [{"id":"1","name":"activeInboundConnections","value":"1"}]
@realisticforeign@stats:5
data: [{"id":"5","name":"topAtSigns","value":"{\"@tigerequivalent\":5}"}]
@realisticforeign@stats
data: [{"id":"1","name":"activeInboundConnections","value":"1"}, {"id":"2","name":"activeOutboundConnections","value":"0"}, {"id":"3","name":"lastCommitID","value":"14"}, {"id":"4","name":"secondaryStorageSize","value":14131}, {"id":"5","name":"topAtSigns","value":"{\"@tigerequivalent\":5}"}, {"id":"6","name":"topKeys","value":"{\"publickey@realisticforeign\":2,\"location.wavi@realisticforeign\":2,\"signing_publickey@realisticforeign\":1,\"public:_notlisted@realisticforeign\":1}"}, {"id":"7","name":"secondaryServerVersion","value":null}]
@realisticforeign@


Secondary Server Synchronization Verbs

In order to synchronize the data between devices, such as mobile phones, and a secondary server, there are two verbs provided on the server: “stats:” and “sync:”. These two verbs provide enough data to see if the device is behind or ahead of the data stored on the secondary server.

Each update of data to the secondary server increments a counter (commitId) which is displayed after each update. The devices also keep track of their counters and then can determine if they are ahead or behind the counter on the secondary server.

If the device is ahead of the secondary server, then the device can use the “update:” verb to update the data. If it is behind the secondary server, then it can use the “sync:” verb to pull the deltas.

This mechanism allows for multiple devices to sync to the same secondary server. For example, a mobile phone, a tablet, and a PC all synching to a single @sign, but also multiple applications on those devices synching to a single secondary server simultaneously. Each application on each device has a copy of the data and can update and sync it at any time.

Syncing is the most complex part of the protocol, and it also influences the way data is stored by applications. As all private data is stored in an encrypted format on the secondary server by the @platform SDK, delta updates of data are not possible because the encryption (AES256) ensures that the encrypted data is different even if a single bit changes.

cconstab@cally:~$ openssl s_client -ign_eof -brief 76103630-0f85-5dec-8a91-364bf93b0e8d.hornet.atsign.zone:2499
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Peer certificate: CN = 76103630-0f85-5dec-8a91-364bf93b0e8d.hornet.atsign.zone
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
@from:@tigerequivalent
data:_ff6dc12b-8b11-4416-81fe-6c4d58da7581@tigerequivalent:57818857-fe08-4390-8731-ac5d48c410ce
@pkam:Iw9eaZ0lIos1euiK+UA9ot/a9/644GvRsgDwRergCwXdzROHH1TMXwsht+WdDYktbAbjOQ28vzf6Sh045aJhHakIUzr6MzLwBiMtEQIDD75DLftKa0eiJrS9Xp7u7546iWzuz9/UDzX02CA5DkXnzwEMBgxKLwsNZOzEDVwG+4jj/IrAU+JPqF93OHJiTFJUgeKp+IEBz1ZWqtOBwP0iYDtyxTD4gs2P9TAZdSfdhHTiFSTmPvPd/40cOwL9YZdNfsACU02ORd/2efmGmem6GcPdjVHb1ve7K4WANaPityM4umEfQBjyW+kmIkmL3dEVUBbu3xZIie+g3pwSHSgdpw==
data:success
@tigerequivalent@stats:3
data: [{"id":"3","name":"lastCommitID","value":"26"}]
@tigerequivalent@sync:24
data:[{"atKey":"cached:public:weather@tigerequivalent","operation":"#","opTime":"2021-07-15 00:00:00.767668Z","commitId":25,"value":"wetter","metadata":{"createdAt":"2021-07-15 00:00:00.767302Z","updatedAt":"2021-07-15 00:00:00.767324Z"}},{"atKey":"@realisticforeign:notify@tigerequivalent","operation":"*","opTime":"2021-07-15 01:19:38.381118Z","commitId":26,"value":"hello","metadata":{"isBinary":"false","isEncrypted":"false","createdAt":"2021-07-15 01:19:38.380727Z","updatedAt":"2021-07-15 01:19:38.380727Z"}}]
@tigerequivalent@

The example above shows connecting to @tigerequivalent by using the “stats:3” verb to find the lastCommitID, then getting the delta values from 24 using the “sync:24” command.

Note these values are public and hence in clear text. With encrypted values, the values would appear in encrypted base64 encoded strings.

Metadata is also synchronized with these commands and typically this data is not encrypted, metadata that needs to be encrypted can be done at the application level via the

Conclusion

The @protocol provides a unique identifier that people, entities and things can own independently. The owner of an @sign can provide public or uniquely end to end encrypted data for other @signs and send notifications in near real-time.

The technology used by the @protocol such as DNS, SSL certificates,TLS, RSA, AES are all mature and widely understood. The architecture provides seamless network traffic navigation of firewalls and network address translation.

The causal effect of the @protocol is far reaching, allowing self sovereign identities, end to end encryption for everything and polymorphic data.

Whilst the @protocol is as simple as possible, most developers will want to use an SDK that further abstracts the wire protocol to the application layer.

The @protocol and the @platform that provides the SDK provides new functionality to developers to provide new experiences to people around the world.

Notes


  1. Currently only the Latin character set is open for registration, along with the full set of emojis. ↩︎