Browse Source

Adding radiks to the docs

Adding in base radiks files
Work in progress

Signed-off-by: Mary Anthony <mary@blockstack.com>
feat/clarity-updates
Mary Anthony 5 years ago
parent
commit
2b0102afc3
  1. 8
      _data/navigation_learn.yml
  2. 1
      _develop/overview_auth.md
  3. 82
      _develop/radiks-collaborate.md
  4. 74
      _develop/radiks-intro.md
  5. 245
      _develop/radiks-models.md
  6. 129
      _develop/radiks-server-extras.md
  7. 247
      _develop/radiks-setup.md
  8. 4
      _develop/storage.md
  9. 2
      _develop/zero_to_dapp_2.md
  10. 2
      _develop/zero_to_dapp_2_win.md
  11. 2
      _develop/zero_to_dapp_3.md
  12. 2
      _develop/zero_to_dapp_3_win.md
  13. 18
      _includes/architecture.md
  14. 2
      _includes/commandline.md
  15. 6
      _includes/question.html
  16. 2
      _org/wallet-install.md
  17. 35
      _storage/overview.md

8
_data/navigation_learn.yml

@ -16,6 +16,14 @@
docs:
- develop/collections
- develop/collection-type
- title: Sharing data
docs:
- develop/radiks-intro
- develop/radiks-setup
- develop/radiks-models
- develop/radiks-collaborate
- develop/radiks-server-extras
- title: Try it! Zero to DApp
docs:

1
_develop/overview_auth.md

@ -4,7 +4,6 @@ permalink: /:collection/:path.html
---
# Understand Blockstack Auth
{:.no_toc}
Blockstack Auth provides single sign on and authentication without third parties or remote servers. On this page, you'll get an overview of authentication from a developer and user perspective. The following topics are covered:

82
_develop/radiks-collaborate.md

@ -0,0 +1,82 @@
---
layout: learn
permalink: /:collection/:path.html
---
# Collaboration
A key feature of Radiks is support for private collaboration between multiple users. Supporting collaboration with client-side encryption and user-owned storage can be complicated, but the patterns to implement it are generally the same for different apps. Radiks provides out-of-the box for collaboration, making it easy to build private, collaborative apps.
Radiks is built in a way that provides maximum privacy and security for collaborative groups. Radiks-server and external users have no knowledge about who is in a group.
### UserGroup Model
The key model behind a collaborative group is `UserGroup`. By default, it only has one attribute, `name`, which is encrypted. You can create multiple subclasses of `UserGroup` later on with different attributes, if you need to.
### General Workflow
The general workflow for creating a collaborative group that can share and edit encrypted models is as follows:
1. The admin of the group creates a new `UserGroup`, which acts as the 'hub' and controls the logic around inviting and removing users.
2. The admin invites one or more other users to a group:
1. The admin specifies the username of the user they want to invite
2. Radiks looks up the user's public key
3. Radiks creates an 'invitation' that is encrypted with the user's public key, and contains information about the `UserGroup`
4. When the invited user 'activates' an invitation, they create a `GroupMembership`, which they can later use to reference information (such as private keys and signing keys) related to the group.
3. Later on, members of the group can create and update models that are related to the group. These models **must** contain a reference to the group, using the attribute `userGroupId`. This allows Radiks to know which keys to use for encryption and signing.
4. The admin of the group can later remove a user from a group. They do this by creating a new private key for signing and encryption, and updating the `GroupMembership` of all users _except_ the user they just removed.
5. After a key is rotated, all new and updated models must use the new key for signing. Radiks-server validates all group-related models to ensure that they're signed with the most up-to-date key.
#### Creating a UserGroup
~~~javascript
import { UserGroup } from 'radiks';
// ...
const group = new UserGroup({ name: 'My Group Name' });
await group.create();
~~~
Calling `create` on a new `UserGroup` will create the group and activate an invitation for the creator of the group.
#### Inviting a User
Use the `makeGroupMembership` method on a `UserGroup` instance to invite a user. The only argument passed to this method is the username of the user you want to invite.
~~~javascript
import { UserGroup } from 'radiks';
const group = await UserGroup.findById(myGroupId);
const usernameToInvite = 'hankstoever.id';
const invitation = await group.makeGroupMembership(usernameToInvite);
console.log(invitation._id); // the ID used to later activate an invitation
~~~
#### Accepting an invitation
Use the `activate` method on a `GroupInvitation` instance to activate an invitation:
~~~javascript
import { GroupInvitation } from 'radiks';
const invitation = await GroupInvitation.findById(myInvitationID);
await invitation.activate();
~~~
#### Viewing all activated UserGroups for the current user
Call `UserGroup.myGroups` to fetch all groups that the current user is a member of:
~~~javascript
import { UserGroup } from 'radiks';
const groups = await UserGroup.myGroups();
~~~
#### Finding a UserGroup
Use the method `UserGroup.find(id)` when fetching a specific UserGroup. This method has extra boilerplate to handle decrypting the model, because the private keys may need to be fetched from different models.
~~~javascript
const group = await UserGroup.find('my-id-here');
~~~

74
_develop/radiks-intro.md

@ -0,0 +1,74 @@
---
layout: learn
permalink: /:collection/:path.html
---
# Radiks the data indexer
The Blockstack Radiks feature enables Blockstack decentralized applications (DApps) to index and store across data belonging to multiple users. Radiks works with Blockstack's Gaia Storage System. Using Radiks, you can build multi-player DApps that:
- index, store, and query complex application data
- query a user's publicly saved data
- display real-time updates that reflect in progress changes
- support collaboration among sets of users
{% include question.html content="I added the word <strong>application</strong> to the complex data bullet above. Your origianl text seemed to make a distinction between publicly saved data and complex data. I assumed applciation data was the something Radiks could store and that was intended here. Was this your intent?"%}
## Why use Radiks?
Many applications server data that users create to share publicly with others, Facebook, Twitter, and Instagram are examples of such applications. Decentralized applications that want to create comparable multi-user experiences must ensure that anything a user creates for public sharing is likewise still under control the creator in the user's Gaia storage.
For example, if Twitter were a decentralized application where many different users creating their own tweets and those tweets are stored in each user's own Gaia storage. In such a situation, developer need a way to track of everyone's tweets, display tweets in user timelines, and perform searches across tweets. Radiks exists to support these kind of scenarios in that it allows applications to query across multiple user data, using complicated queries like text search, joins, and filters. Radiks allows applications to query data in a performant and flexible way.
{% include question.html content="Can one Radiks server support multiple client applications or is a single server required for each application?"%}
## How Radiks works with application data
Radiks consists of a database, a pre-built server, and a client. Each application adds Radiks client library to their application. With this library a developer models their application data. The model defines an applications data schema for the Radiks server. Then, you can use calls to this model to write and query data that uses that schema. When ever an application saves or updates data on behalf of a user, Radiks follows this process:
1. Encrypts private user data on the client-side.
2. Saves a raw JSON of this encrypted data in the user's Gaia storage.
3. Stores the encrypted data on the Radiks server.
{% include question.html content="You didn't state this in the original but I am assuming the data is user data not just general application data. Is this correct? See the following paragraph which was taken from your server docs, in particular you had the last sentence regarding unencrypted data. Still isn't clear to me when is data in unencrypted and how it is identified from data the user wants signed." %}
Radiks stores both public data and sensitive, non-private data. Radiks encrypts sensitive data before it leaves the client. Your application can query Radiks for public data and then decrypt the sensitive information on the client. This means that the server is only able to return queries for unencrypted data.
## How Radiks authorizes writes
Radiks must ensure that user's own any data they are writing. To ensure this, Radiks creates and manages *signing keys*. These keys sign all writes that a user performs. Radiks-server validates all signatures before performing a write. This guarantees that a user is not able to over-write another user's data.
Radiks-server also is built to support writes in a collaborative, but private, situation. For example, consider a collaborative document editing application, where users can create organizations and invite users to that organization. All users in that organization have read and write privileges to the organization data. These organizations have single shared key that is used to sign and encrypt data.
When an organization administrator needs to remove a user from the group, they'll revoke a previous key and create a new one. Radiks is aware of these relationships, and will only support writes that are signed with the current active key related to an organization.
## Is Radiks decentralized
Although Radiks applications rely on a centrally-hosted database, an application using Radiks remains fundamentally decentralized. A DApp that uses Radiks has these characteristics.
<table class="uk-table">
<tr>
<td>Built on decentralized authentication</td>
<td> Radiks is deeply tied to Blockstack authentication, which uses a blockchain and Gaia to give you full control over your user data.
</tr>
<tr>
<td>No data lock-in</td>
<td><p>All user data is first stored in Gaia before encrypted with the user's keys and stored in Radiks. This process means the user still controls their data for as long as they need to. If the application's Radiks server shuts down, the user can still access their data. And, without application to the user's signing keys, the application cannot decrypt the data. Users may also backup or migrate their application data from Gaia.
</p></td>
</tr>
<tr>
<td>Censorship resistance</td>
<td><p>All data is also stored in Gaia, no third-party can revoke access to this data.
</p></td>
</tr>
<tr>
<td>Maximum privacy</td>
<td><p>All data is encrypted on the client side before being stored anywhere using Blockstack authorization. The application host cannot inspect, sell, or use user data in any way that a user doesn't explicitly authorize.
</p></td>
</tr>
</table>
If you are not familiar with Gaia or Blockstack authentication, see
[read the Gaia documentation](({{site.baseurl}}/storage/overview.html) and [start with the overview of Blockstack auth](overview_auth.html).

245
_develop/radiks-models.md

@ -0,0 +1,245 @@
---
layout: learn
permalink: /:collection/:path.html
---
# Create and use models
To create a model class, first import the `Model` class from radiks. Then, create a class that extends this model, and provide a schema.
**Important**: Make sure you add a static `className` property to your class. This is used when storing and querying information. If you don't add this, radiks will default to the actual model's class name. However, in production, your code will likely be minified, and the actual class name will be different. For this reason, it's highly recommended that you define the `className` manually.
#### Schema
The first static property you'll need to define is a schema. Create a static `schema` property on your class to define it. Each `key` in this object is the name of the field. The value is whatever type you want the field to be, or you can pass some options.
If you don't want to include any options, just pass the class for that field, like `String`, `Boolean`, or `Number`.
To include options, pass an object, with a mandatory `type` field. The only supported option right now is `decrypted`. This defaults to `false`, but if you provide `true`, then this field will not be encrypted before storing data publicly. This is useful if you want to be able to query this field when fetching data.
**Important**: do not add the `decrypted` option to fields that contain sensitive user data. Remember, because this is decentralized storage, anyone can read the user's data. That's why encrypting it is so important. If you want to be able to filter sensitive data, then you should do it on the client-side, after decrypting it. A good use-case for storing decrypted fields is to store a `foreignId` that references a different model, for a "belongs-to" type of relation.
#### Defaults
Include an optional `defaults` static property to define default values for a field.
#### Example
~~~javascript
import { Model } from 'radiks';
class Person extends Model {
static className = 'Person';
static schema = {
name: String,
age: Number,
isHuman: Boolean,
likesDogs: {
type: Boolean,
decrypted: true // all users will know if this record likes dogs!
}
}
static defaults = {
likesDogs: true
}
}
~~~
### Using models
All model instances have an `_id` attribute. If you don't pass an `_id` to the model (when constructing it), then an `_id` will be created automatically using [`uuid/v4`](https://github.com/kelektiv/node-uuid). This `_id` is used as a primary key when storing data, and would be used for fetching this model in the future.
In addition to automatically creating an `_id` attribute, radiks also creates a `createdAt` and `updatedAt` property when creating and saving models.
#### Constructing a model
To create an instance of a model, pass some attributes to the constructor of that class:
~~~javascript
const person = new Person({
name: 'Hank',
isHuman: false,
likesDogs: false // just an example, I love dogs!
})
~~~
#### Fetching a model
To fetch an existing model, first construct it with a required `id` property. Then, call the `fetch()` function, which returns a promise.
~~~javascript
const person = await Person.findById('404eab3a-6ddc-4ba6-afe8-1c3fff464d44');
~~~
After calling `fetch`, radiks will automatically decrypt all encrypted fields.
#### Accessing model attributes
All attributes (other than `id`) are stored in an `attrs` property on the model.
~~~javascript
const { name, likesDogs } = person.attrs;
console.log(`Does ${name} like dogs?`, likesDogs);
~~~
#### Updating a model
To quickly update multiple attributes of a model, pass those attributes to the `update` function.
~~~javascript
const newAttributes = {
likesDogs: false,
age: 30
}
person.update(newAttributes)
~~~
Note that calling `update` does **not** save the model.
#### Saving a model
To save a model to Gaia and MongoDB, call the `save` function. First, it encrypts all attributes that do not have the `decrypted` option in their schema. Then, it saves a JSON representation of the model in Gaia, as well as in MongoDB. `save` returns a promise.
~~~javascript
await person.save();
~~~
#### Deleting a model
To delete a model, just call the `destroy` method on it.
~~~javascript
await person.destroy();
~~~
### Querying models
To fetch multiple records that match a certain query, use the class's `fetchList` function. This method creates an HTTP query to Radiks-server, which then queries the underlying database. Radiks-server uses the [`query-to-mongo`](https://github.com/pbatey/query-to-mongo) package to turn an HTTP query into a MongoDB query. Read the documentation for that package to learn how to do complex querying, sorting, limiting, etc.
Here are some examples:
~~~javascript
const dogHaters = await Person.fetchList({ likesDogs: false });
~~~
Or, imagine a `Task` model with a `name`, a boolean for `completed`, and an `order` attribute.
~~~javascript
class Task extends Model {
static className = 'Task';
static schema = {
name: String,
completed: {
type: Boolean,
decrypted: true,
},
order: {
type: Number,
decrypted: true,
}
}
}
const tasks = await Task.fetchList({
completed: false,
sort: '-order'
})
~~~
### Counting models
You can also get the count record directly.
~~~javascript
const dogHaters = await Person.count({ likesDogs: false });
// dogHaters is the count number
~~~
### Fetching models created by the current user
Use the `fetchOwnList` method to find models that were created by the current user. By using this method, you can preserve privacy, because Radiks uses a `signingKey` that only the current user knows.
```javascript
const tasks = await Task.fetchOwnList({
completed: false
});
```
### Managing relational data
It is common for applications to have multiple different models, where some reference another. For example, imagine a task-tracking application where a user has multiple projects, and each project has multiple tasks. Here's what those models might look like:
~~~javascript
class Project extends Model {
static className = 'Project';
static schema = { name: String }
}
class Task extends Model {
static className = 'Task';
static schema = {
name: String,
projectId: {
type: String,
decrypted: true,
}
completed: Boolean
}
}
~~~
Whenever you save a task, you'll want to save a reference to the project it's in:
~~~javascript
const task = new Task({
name: 'Improve radiks documentation',
projectId: project._id
})
await task.save();
~~~
Then, later you'll want to fetch all tasks for a certain project:
~~~javascript
const tasks = await Task.fetchList({
projectId: project._id,
})
~~~
Radiks lets you define an `afterFetch` method, which you can use to automatically fetch child records when you fetch the parent instance.
~~~javascript
class Project extends Model {
static className = 'Project';
static schema = { name: String }
async afterFetch() {
this.tasks = await Task.fetchList({
projectId: this.id,
})
}
}
const project = await Project.findById('some-id-here');
console.log(project.tasks); // will already have fetched and decrypted all related tasks
~~~
### Extending the user model
You can extend the default user model to add your own fields.
~~~javascript
import { User } from 'radiks';
// For example I want to add a public name on my user model
class MyAppUserModel extends User {
static schema = {
...User.schema,
name: {
type: String,
decrypted: true,
},
};
}
~~~

129
_develop/radiks-server-extras.md

@ -0,0 +1,129 @@
---
layout: learn
permalink: /:collection/:path.html
---
# Other ways to use Radiks
### Running a custom Radiks-server
If you're using an [express.js](https://expressjs.com/) server to run your application, it's probably easiest to use the Radiks-server middleware. This way, you won't have to run a separate application server and Radiks server.
Radiks-server includes an easy-to-use middleware that you can include in your application:
```javascript
const express = require('express');
const { setup } = require('radiks-server');
const app = express();
setup().then(RadiksController => {
app.use('/radiks', RadiksController);
});
```
The `setup` method returns a promise, and that promise resolves to the actual middleware that your server can use. This is because it first connects to MongoDB, and then sets up the middleware with that database connection.
The `setup` function accepts an `options` object as the first argument. Right now, the only option supported is `mongoDBUrl`. If you aren't using environment variables, you can explicitly pass in a MongoDB URL here:
```javascript
setup({
mongoDBUrl: 'mongodb://localhost:27017/my-custom-database',
}).then(RadiksController => {
app.use('/radiks', RadiksController);
});
```
### Accessing the MongoDB Collection
#### Using `getDB` to manually connecting to the MongoDB collection
Radiks-server keeps all models inside of a collection. You can use the `getDB` function to access this collection. [See the MongoDB Collection reference](https://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html) for documentation about how you can interact with this collection.
```js
const { getDB } = require('radiks-server');
const mongo = await getDB(MONGODB_URL);
```
#### Migration from Firebase (or anywhere else)
Migrating data from Firebase to Radiks-server is simple and painless. You can create a script file to fetch all the firebase data using their API. Then, you can use your MONGOD_URI config to use the `mongodb` npm package.
```js
// Script for transfering users from Firebase to Radiks-server
const { getDB } = require('radiks-server');
const { mongoURI } = require('......'); // How you import/require your mongoURI is up to you
const migrate = async () => {
// `mongo` is a reference to the MongoDB collection that radiks-server uses.
// You can add or edit or update data as necessary.
const mongo = await getDB(mongoURI);
/**
* Call code to get your users from firebase
* const users = await getUsersFromFirebase();
* OR grab the Firebase JSON file and set users to that value
* How you saved your user data will proably be different than the example below
*/
const users = {
'-LV1HAQToANRvhysSClr': {
blockstackId: '1N1DzKgizU4rCEaxAU21EgMaHGB5hprcBM',
username: 'kkomaz.id',
},
};
const usersToInsert = Object.values(users).map(user => {
const { username } = user;
const doc = {
username,
_id: username,
radiksType: 'BlockstackUser',
};
const op = {
updateOne: {
filter: {
_id: username,
},
update: {
$setOnInsert: doc,
},
upsert: true,
},
};
return op;
});
await mongo.bulkWrite(usersToInsert);
};
migrate()
.then(() => {
console.log('Done!');
process.exit();
})
.catch(error => {
console.error(error);
process.exit();
});
```
### Options
You can specify some options while initiating the Radiks server.
```javascript
const { setup } = require('radiks-server');
setup({
...myOptions,
});
```
Available options:
- `mongoDBUrl` - The MongoDB URL for the Radiks server
- `maxLimit` - The maximum `limit` field used inside the mongo queries - default to 1000

247
_develop/radiks-setup.md

@ -0,0 +1,247 @@
---
layout: learn
permalink: /:collection/:path.html
---
# Set-up Radiks for your DApp
{:.no_toc}
Using Radiks with your application requires a Radiks server and a client application constructed to use the server. In this article, you learn how to install, setup, and run a pre-packaged Radiks server that connects to MongoDB. You also learn how to establish your DApp application as a client for that server.
* TOC
{:toc}
## Task 1. Set up your Radiks server
Radiks-server is a `node.js` application that uses [MongoDB](https://www.mongodb.com/) as an underlying database.
### Install and configure MongoDB
In the future, Radiks-server will support various different databases, but right now only MongoDB 3.6 or higher is supported. MongoDB 3.6 and higher contains fixes required for naming patterns in keys.
{% include note.html content="The steps assumes you want to install and run the MongoDB software locally on your workstation for testing and development. If you are deploying for a production application, you would install MongoDB on your application server or on a server connected to it. " %}
1. <a href="https://docs.mongodb.com/manual/administration/install-community/" target="_blank">Download and install MongoDB 3.6 or higher</a> on your workstation.
You can also install MongoDB using your favorite package manager, for example, Homebrew is recommended for macOS. If you are testing on a local workstation, you can use a `docker` image instead of installing locally.
2. Start the MongoDB service and verify it is running.
3. On your MongoDB instance, create a database for your application data.
You can use the <a href="https://docs.mongodb.com/manual/mongo/" target="_blank">Mongo shell</a> to do this or you can <a href="https://www.mongodb.com/download-center/compass" target="_blank">install the MongoDB Compass</a> software to explore and work with MongoDB data.
4. Create a username/password combination with `root` privileges on your new database.
### Install and start the Radiks server
The easiest way to run `radiks-server` is to use the pre-packaged `node.js` server.
1. Install the `radiks-server` on a workstation or server.
```bash
npm install -g radiks-server
```
Or, if you prefer `yarn`:
```bash
yarn global add radiks-server
```
The default port for Mongodb is `27017`, your instance may be configured differently. By default, Radiks-server will use `'MongoDB://localhost:27017/radiks-server'` as the `MongoDB_URI` value. This is suitable for local testing, but in production, you'll want to change the hostname and possible the database name.
3. Start the `radiks-server` in the command line to confirm your installation.
```
$ radiks-server
(node:37750) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
radiks-server is ready on http://localhost:1260
```
The `radiks-server` defaults to running on port `1260`. To change the default port, specify the `PORT` environment variable in your environment.
4. By default the server is running at `http://localhost:1260`
4. Stop the `radiks` server process after you confirm it runs and your installation was a success.
## Task 2. Set up your application
You must set up your application to use Radiks. This requires installing the `radiks` client package and then configuring your application to connect to your Radiks server.
### Install the radiks client software
If you are using `blockstack.js` version 18 or earlier, you must use the Radiks version 0.1.\*, otherwise if you're using `blockstack.js` version 19 or higher, use Radiks 0.2.\* .
1. Change directory to the root of you application code.
2. Install the install the `radiks` client package.
<table class="uk-table uk-table-small">
<thead>
<tr>
<td><strong>Use npm</strong></td>
<td><strong>Use yarn</strong></td>
</tr>
</thead>
<tbody>
<tr>
<td><code class="highlighter-rouge">npm install --save radiks</code></td>
<td><code class="highlighter-rouge">yarn add radiks</code></td>
</tr>
</tbody>
</table>
### Configure the MongoDB for your application
1. Start the mongo shell application.
```
$ mongo
MongoDB shell version v4.2.0
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("8d43cf80-490d-4cac-8bd6-40eec5c128de") }
MongoDB server version: 4.2.0
....
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
>
```
2. Create a new database for your application.
```
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> use test1
switched to db test1
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> db.createUser({user: "admin", pwd:"foobar1",roles: ["readWrite","dbAdmin"]});
Successfully added user: { "user" : "admin", "roles" : [ "readWrite", "dbAdmin" ] }
```
3. Add a user with administrative rights to the database.
```
> db.createUser({user: "admin", pwd:"foobar1",roles: ["readWrite","dbAdmin"]});
Successfully added user: { "user" : "admin", "roles" : [ "readWrite", "dbAdmin" ] }
```
### Configure your application to use
3. Configure your application to use your `radiks-server`.
To configure your applciation as a `radiks` client, use code that looks like this when starting up your application:
```js
import { UserSession, AppConfig } from 'blockstack';
import { configure } from 'radiks';
const userSession = new UserSession({
appConfig: new AppConfig(['store_write', 'publish_data'])
})
configure({
apiServer: 'http://localhost:1260',
userSession
});
```
For more information on configuring and writing a Radiks a client application, see [the Radiks client](https://github.com/blockstack-radiks/radiks) repository.
4. Create an `MONGODB_URI` environment variable on the same machine where you are running the `radiks-server`.
Use the `mongodb://username:password@host:port/db_name` format for your variable. For example, to set this variable in a `bash` shell:
```bash
export MONGODB_URI="mongodb://admin:foobar1@localhost:27017/test1"
```
mongodb://admin:foobar1@127.0.0.1:27017/test1
5. Build and run your application.
### Configuration
To set up radiks.js, you only need to configure the URL that your Radiks-server instance is running on. If you're using the pre-built Radiks server, this will be `http://localhost:1260`. If you're in production or are using a custom Radiks server, you'll need to specify exactly which URL it's available at.
Radiks also is compatible with version 19 of blockstack.js, which requires you to configure a `UserSession` object to handle all user-data-related methods. You'll need to define this and pass it to your Radiks configuration, so that Radiks can know how to fetch information about the current logged in user.
To configure radiks, use code that looks like this when starting up your application:
~~~javascript
import { UserSession, AppConfig } from 'blockstack';
import { configure } from 'radiks';
const userSession = new UserSession({
appConfig: new AppConfig(['store_write', 'publish_data'])
})
configure({
apiServer: 'http://my-radiks-server.com',
userSession
});
~~~
### Authentication
Most of your code will be informed by following [Blockstack's authentication documentation](https://github.com/blockstack/blockstack.js/blob/master/src/auth/README.md).
After your user logs in with Blockstack, you'll have some code to save the user's data in localStorage. You'll want to use the same `UserSession` you configured with Radiks, which can be fetched from the `getConfig` method.
~~~javascript
import { User, getConfig } from 'radiks';
const handleSignIn = () => {
const { userSession } = getConfig();
if (userSession.isSignInPending()) {
await userSession.handlePendingSignIn();
await User.createWithCurrentUser();
}
}
~~~
Calling `User.createWithCurrentUser` will do a few things:
1. Fetch user data that Blockstack.js stores in `localStorage`
2. Save the user's public data (including their public key) in Radiks-server
3. Find or create a signing key that is used to authorize writes on behalf of this user
4. Cache the user's signing key (and any group-related signing keys) to make signatures and decryption happen quickly later on
## Models
Creating models for your application's data is where radiks truly becomes helpful. We provide a `Model` class that you can extend to easily create, save, and fetch models.
### Quick start
```javascript
import { Model, User } from 'radiks';
class Todo extends Model {
static className = 'Todo';
static schema = { // all fields are encrypted by default
title: String,
completed: Boolean,
}
};
// after authentication:
const todo = new Todo({ title: 'Use Radiks in an app' });
await todo.save();
todo.update({
completed: true,
});
await todo.save();
const incompleteTodos = await Todo.fetchOwnList({ // fetch todos that this user created
completed: false
});
console.log(incompleteTodos.length); // 0
```

4
_develop/storage.md

@ -14,6 +14,10 @@ The Blockstack Platform stores application data in the Gaia Storage System. Tran
{% include note.html content="<ul> <li>Blockstack Gaia Storage APIs and on-disk format will change in upcoming pre-releases breaking backward compatibility. File encryption is currently opt-in on a file by file basis.</li> <li>Certain storage features such as collections are not implemented in the current version. These features will be rolled out in future updates.</li> </ul>" %}
## How data is stored
Gaia storage is a key-value store.
## Creating a file

2
_develop/zero_to_dapp_2.md

@ -7,7 +7,7 @@ image: /assets/img/zero-to-dapp.png
# 2 - Learn about the platform
{:.no_toc}
**Zero-to-DApp 2 of 4 for MacOS/Linux (or [Windows](zero_to_dapp_2_win.html))**
**Zero-to-DApp 2 of 4 for macOS/Linux (or [Windows](zero_to_dapp_2_win.html))**
In this part, you learn how the Blockstack platform lowers the barriers to
building with blockchain technology. You'll set up all the prerequisites you

2
_develop/zero_to_dapp_2_win.md

@ -7,7 +7,7 @@ image: /assets/img/zero-to-dapp.png
# 2 - Learn about the platform (Windows)
{:.no_toc}
**Zero-to-DApp 2 of 4 for Windows (or [MacOS/Linux](zero_to_dapp_2.html))**
**Zero-to-DApp 2 of 4 for Windows (or [macOS/Linux](zero_to_dapp_2.html))**
In this part, you learn how the Blockstack platform lowers the barriers to
building with blockchain technology. You'll set up all the prerequisites you

2
_develop/zero_to_dapp_3.md

@ -7,7 +7,7 @@ image: /assets/img/zero-to-dapp.png
# 3 - Customize your kingdom
{:.no_toc}
**Zero to DAPP 3 of 4 for MacOS/Linux (or [Windows](zero_to_dapp_3_win.html))**
**Zero to DAPP 3 of 4 for macOS/Linux (or [Windows](zero_to_dapp_3_win.html))**
In this page, you examine and modify the Animal Kingdom DApp [you built in part
2](zero_to_dapp_2.html). You'll review the underlying code and locate the

2
_develop/zero_to_dapp_3_win.md

@ -7,7 +7,7 @@ image: /assets/img/zero-to-dapp.png
# 3 - Customize your kingdom (Windows)
{:.no_toc}
**Zero to DAPP 3 of 4 for Windows (or [MacOS/Linux](zero_to_dapp_3.html))**
**Zero to DAPP 3 of 4 for Windows (or [macOS/Linux](zero_to_dapp_3.html))**
In this page, you examine and modify the Animal Kingdom DApp [you built in part
2](zero_to_dapp_2.html). You'll review the underlying code and locate the

18
_includes/architecture.md

@ -3,20 +3,14 @@
Blockchains require consensus among large numbers of people, so they can be slow. Additionally, a blockchain is not designed to hold a lot of data. This means using a blockchain for every bit of data a user might write and store is expensive. For example, imagine if an application were storing every tweet in the chain.
Blockstack addresses blockchain performance problems using a layered approach. At the base of the system is a blockchain and the Blockstack Naming System (BNS). The blockchain governs ownership of names (identities) in the system, names such as domain names, usernames, and application names.
Blockstack addresses blockchain performance problems using a layered approach. The base layer consists of the Stacks blockchain and the Blockstack Naming System (BNS). The blockchain governs ownership of identities in the Blockstack network. Identities can be names such as domain names, usernames, or application names.
Names in Blockstack correspond to routing data in the OSI stack. The routing data is stored in the Atlas Peer Network, the second layer. Every core node that joins the Blockstack Network is able to obtain an entire copy of this routing data. Blockstack uses the routing data to associate names (usernames, domains, and application names) with a particular storage location.
When an identity is created, its creation is recorded in the Stacks blockchain. Identities make up the primary data stored into the Stacks blockchain. These identities correspond to routing data in the OSI stack. The routing data is stored in the Atlas Peer Network, the second layer. Every core node that joins the Blockstack Network is able to obtain an entire copy of this routing data. Blockstack uses the routing data to associate identities (domain names, user names, and application names) with a particular storage location in the final layer, the Gaia Storage System.
The final layer is the Gaia Storage System. A Gaia system consists of a _hub
service_ and storage resource on a cloud software provider such as Azure,
DigitalOcean, Amazon EC2, and so forth. Typically the compute resource and the
storage resource belong to same cloud vendor. Gaia currently has
driver support for S3 and Azure Blob Storage, but the driver model allows for
other backend support as well.
A Gaia Storage System consists of a _hub service_ and storage resource on a cloud software provider. The storage provider can be any commercial provider such as Azure, DigitalOcean, Amazon EC2, and so forth. Typically the compute resource and the storage resource reside same cloud vendor, though this is not a requirement. Gaia currently has driver support for S3 and Azure Blob Storage, but the driver model allows for other backend support as well.
Because Gaia stores application and user data off the blockchain, a Blockstack
DApp is typically more performant than DApps created on other blockchains.
Moreover, users choose where their data lives, and Gaia enables applications
to access that user data via a uniform API. When the user logs in,
Gaia stores data as a simple key-value store. When an identity is created, a corresponding data store is associated with that identity on Gaia. When a user logs into a dApp,
the authentication process gives the application the URL of a Gaia hub, which
then writes to storage on behalf of that user.
Within Blockstack, then, the Stacks blockchain stores only identity data. Data created by the actions of an identity is stored in a Gaia Storage System. Each user has profile data. When a user interacts with a decentralized dApp that application stores application data on behalf of the user. Because Gaia stores user and application data off the blockchain, a Blockstack DApp is typically more performant than DApps created on other blockchains.

2
_includes/commandline.md

@ -60,7 +60,7 @@ To see the usage and options for the command in general, enter `blockstack-cli`
## How to install the command line
{:.no_toc}
You must have [Node.js](https://nodejs.org/en/download/) v8 or higher (v10 recommended). MacOS and Linux users can avoid `sudo` or [permissions problems](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally) or by using [`nvm`](https://github.com/nvm-sh/nvm). These instructions assume you are using a macOS or Linux system.
You must have [Node.js](https://nodejs.org/en/download/) v8 or higher (v10 recommended). macOS and Linux users can avoid `sudo` or [permissions problems](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally) or by using [`nvm`](https://github.com/nvm-sh/nvm). These instructions assume you are using a macOS or Linux system.
To install the command line, do the following:

6
_includes/question.html

@ -1 +1,5 @@
<div class="uk-alert-danger uk-card" uk-alert><b>QUESTION FOR REVIEWERS:</b> {{include.content}}</div>
<<<<<<< HEAD
<div class="uk-alert-danger uk-card" uk-alert><b>QUESTION FOR REVIEWERS:</b> {{include.content}}</div>
=======
<div class="uk-alert-danger uk-card" uk-alert><b>QUESTION FOR REVIEWERS:</b> {{include.content}}</div>
>>>>>>> 6350bd1... Adding in base radiks files

2
_org/wallet-install.md

@ -21,7 +21,7 @@ by Blockstack PBC." %}
## Mac Installation
1. <a href="https://wallet.blockstack.org" target="\_blank">Go to the wallet download page</a> in your browser.
2. Select the **MacOS Download** button.
2. Select the **macOS Download** button.
This button downloads the software to your computer.

35
_storage/overview.md

@ -23,18 +23,14 @@ The following diagram depicts the Blockstack architecture and Gaia's place in it
## User control or how is Gaia decentralized?
A Gaia hub runs as a service which writes to data storage. The hub service
A Gaia hub runs as a service which writes to data storage. The storage itself is a simple key-value store. The hub service
writes to data storage by requiring a valid authentication token from a requestor. Typically, the hub service runs on a compute resource and the storage itself on separate, dedicated storage resource. Typically, both resources belong to the same cloud computing provider.
![Gaiastorage](/storage/images/gaia-storage.png)
Gaia's approach to decentralization focuses on user control of data and its
storage. If a user can choose which Gaia hub provider to use, then that choice
is all the decentralization required to enable user-controlled applications.
Gaia's approach to decentralization focuses on user control of data and its storage. Users can choose a Gaia hub provider. If a user can choose which Gaia hub provider to use, then that choice is all the decentralization required to enable user-controlled applications. Moreover, Gaia a uniform API to access for applications to access that data.
The control of user data lies in the way that user data is accessed.
When an application fetches a file `data.txt` for a given user `alice.id`, the
lookup will follow these steps:
The control of user data lies in the way that user data is accessed. When an application fetches a file `data.txt` for a given user `alice.id`, the lookup will follow these steps:
1. Fetch the `zonefile` for `alice.id`.
2. Read her profile URL from her `zonefile`.
@ -43,35 +39,18 @@ lookup will follow these steps:
5. Read the `gaiaHubUrl` (e.g. `https://gaia.alice.org/`) out of the profile
6. Fetch the file from `https://gaia.alice.org/data.txt`.
Because `alice.id` has access to her zonefile, she can change where her profile
is stored. For example, she may do this if the current profile's service or
storage is compromised. To change where her profile is stored, she changes her
Gaia hub URL to another Gaia hub URL from another hub provider. If Alice has
sufficient compute and storage resources herself, she may run her own Gaia
Storage System and bypass a commercial Gaia hub provider all together.
Because `alice.id` has access to her zonefile, she can change where her profile is stored. For example, she may do this if the current profile's service provider or storage is compromised. To change where her profile is stored, she changes her Gaia hub URL to another Gaia hub URL. If a user has sufficient compute and storage resources, a user may run their own Gaia Storage System and bypass a commercial Gaia hub provider all together.
{% include note.html content="Users with existing identities cannot yet migrate
their data from one hub to another." %}
Applications writing directly on behalf of Alice do not need to perform a
lookup. Instead, the Blockstack <a
href="http://blockstack.github.io/blockstack.js/index.html"
target="\_blank">authentication flow</a> provides Alice's chosen application
root URL to the application. This authentication flow _is also_ within Alice's
control because Alice's browser _must_ generate the authentication response.
Applications writing directly on behalf of `alice.id` do not need to perform a lookup. Instead, the Blockstack <a href="http://blockstack.github.io/blockstack.js/index.html" target="\_blank">authentication flow</a> provides Alice's chosen application root URL to the application. This authentication flow _is also_ within Alice's control because Alice's browser _must_ generate the authentication response.
## Understand data storage
A Gaia hub stores the written data _exactly_ as given. It offers minimal
guarantees about the data. It does not ensure that data is validly formatted,
contains valid signatures, or is encrypted. Rather, the design philosophy is
that these concerns are client-side concerns.
Client libraries (such as `blockstack.js`) are capable of providing these
guarantees. Blockstack used a liberal definition of the <a href="https://en.wikipedia.org/wiki/End-to-end_principle" target="\_blank">end-to-end principle</a> to
guide this design decision.
A Gaia hub stores the written data _exactly_ as given. It offers minimal guarantees about the data. It does not ensure that data is validly formatted, contains valid signatures, or is encrypted. Rather, the design philosophy is that these concerns are client-side concerns.
Client libraries (such as `blockstack.js`) are capable of providing these guarantees. Blockstack used a liberal definition of the <a href="https://en.wikipedia.org/wiki/End-to-end_principle" target="\_blank">end-to-end principle</a> to guide this design decision.
## Gaia versus other storage systems

Loading…
Cancel
Save