Coder Social home page Coder Social logo

radiks's Introduction

Radiks

A client-side framework for building model-driven decentralized applications on top of Blockstack storage and authentication.

Documentation

For documentation on using Radiks, visit the Blockstack documentation for developers.

Development

To compile with babel, run:

yarn compile
# or, to auto-compile when files change
yarn compile-watch

To run tests:

yarn test

To run eslint:

yarn eslint

radiks's People

Contributors

dependabot[bot] avatar friedger avatar gravityblast avatar hstove avatar pradel avatar reedrosenbluth avatar yknl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

radiks's Issues

Question: async afterFetch not being called when extending User model

When extending a user model, I tried calling the async afterFetch() function to add some relational information. I placed a debugger hoping it would hit when I fetch a single model via findOne however it does not hit.

screenshot of atom 3-4-19 7-22-47 pm

My workaround for this was to create a separate function

async addBasicInfo() {
  ...
}

then calling that function after the fetch is completed

  const user = await DebutUser.findOne({ username: action.payload.username })
  const debutUser = await user.addBasicInfo()

It would be nice if i could keep all the logic contained in the model itself as opposed to calling it on the user instance. Thoughts?

User is null error

Maybe I'm missing something in the documentation, but I've got the radiks-server running, I've got a local mongo db running, and I have the following code in my client:

async componentDidMount() {
    await configure({
      apiServer: 'http://localhost:1260'
    });
    if (isSignInPending()) {
      handlePendingSignIn().then((userData) => {
        window.location = window.location.origin;
      });
    } else {
      await User.createWithCurrentUser(); //Doing this here simple because I don't want to sign in every time to test it.
    }
  }

The result is TypeError: user is null. I feel like I've followed the documentation exactly, so maybe it's just the fact that I'm using User.createWithCurrentUser() in the componentDidMount lifecycle event?

Unhandled promise rejection:

Anyone using radiks run into a mongoerror: topology was destroyed error? I saw this happening locally first now happening on production. I had to restart my dynos (heroku) but I know that doesnt actually fix the root cause. I looked at the heroku logs and when doing the POST for radiks/models/crawl it gets an error saying the service instance pool was destroyed. This is pretty bad cause basically the whole app breaks.

image

Posted on behalf of Alex Lee

Issue with retrieving UserGroups

I'm having an issue with retrieving UserGroups within my app after logging out and then logging in. If I create a UserGroup, I'm able to access that user group while still logged in with my current session. However, upon logging out and logging back in to the same app, when I retrieve my group memberships, decryption errors are thrown, and the name and members do not get decrypted.

Steps to reproduce:

After user is logged in, create a new group:
const group = new UserGroup({ name: 'my new group' }); await group.create();
Check to make sure I have group membership:
UserGroup.myGroups().then(console.log);
This shows an array with the group I just created (with attrs.name === 'my new group').

Log out
const { userSession } = getConfig(); userSession.signUserOut();

Log back into app, then log my groups again:
UserGroup.myGroups().then(console.log);

Now the same group I just created does show up (the _id property matches), but the name and members properties (under attrs) are encrypted (They are objects with cipherTask, ephemeralPK, iv, and mac properties.) I see error logs from their retrieval:
Decryption error for key: 'members': num.words is null
Decryption error for key: 'name': num.words is null

One other strange thing: at this point, if I create a group and retrieve it using UserGroup.myGroups, I will only see the group I just created, and it will be properly decrypted. I will not see the group that I created during my last session. However, if I log out and log back in again, I'll see both of the groups that I have created, and both will be encrypted (with attendant Decryption error messages).

Thanks for your help, this is a really cool library! Please let me know if I'm doing anything incorrectly.

Bug/Question - Custom User model extended adds new entry on update

Currently on my application I have a model that extends the User model. Fetching and retrieving information is working properly however when I update an attribute it seems to generate a new document entry.

Works (no new entry)

https://github.com/kkomaz/debut/blob/user-profile-image/src/sagas/user/setUserAvatar.js#L9

  • Finding the user via User model
  • update and save
  • refetch via DebutUser with the extra attributes

Doesn't Work

https://github.com/kkomaz/debut/blob/user-profile-image/src/sagas/user/setUserAvatar.js#L8

  • find the user via debutUser model
  • update and save
  • Creates a new entry

I'm guessing it has to do with the wrapped modeling.

screenshot of opera 3-4-19 7-13-19 pm

413 ERROR for this type of fetch

notifs = await Notification.fetchList({
            offset,
            limit,
            author: {
                $ne: username
            },
            listId: listIds,
            sort: '-createdAt'
        });

Where listIds is an array
This should fetch Notification models with listId values that are in the listIds array.

Is there a limit to how long the listIds array is?

I'm currently having a problem where it's giving me 431 error when the length of listIds array is greater than or equal to 160.

Is there a better way to query Notifications? or a workaround for this?

Is there a way to update/change model schema of existing Model instances?

say you have this
Post Model with this schema

{
 title: String,
 body: String
}

Then saved a Post with that schema
later on, you want to add a poop reaction
so you want an updated schema that would look like this:

{
 title: String,
 body: String,
 reactions: Number
}

What is the best way to implement that?

`UserGroup undefined` error when activating GroupInvitation.

(Assuming #76 is resolved)

I got UserGroup undefined errors when activating a GroupInvitation.
The line below would be the problem.

https://github.com/blockstack/radiks/blob/0d97225e9b828d5348960236fdd4b83c266cbdaa/src/models/group-membership.ts#L91

The code above is trying to get the UserGroup of a GroupMembership model.

https://github.com/blockstack/radiks/blob/0d97225e9b828d5348960236fdd4b83c266cbdaa/src/models/group-membership.ts#L40

When the GroupMembership's UserGroup is deleted, it makes sense that the error would occur.

Should radiks handle this situation or should the app dev? @hstove

Compatibility with UserSession API + Storage Strategies

So I know that you've been active on the PR for the updates to remove dependency on localstorage and I didn’t know if there was going to be any work needed to incorporate these changes and allow use of this library in a node environment?

erro in use without '_id'?

preuse collections with col1, it's ok and then wrong without '_id':

helpers.js?debc:139 Uncaught (in promise) TypeError: Cannot read property '_id' of undefined
    at addPersonalSigningKey (helpers.js?debc:139)
    at eval (user.js?6e98:144)

but change collection to new col2, it's ok again.

what's wrong on col1?

Provide a way to create an invitation for users that haven't signed up yet

When using UserGroups, you can invite users, but they have to have already signed up for the app. This is because Radiks needs their public key, in order to encrypt their invitation.

One cool feature would be a way to create a generic invitation that any user can 'activate', if they are provided with some secret key, which would be used to decrypt the invitation.

Allow models to only store on gaia

Some models might not needed to be stored on the radiks server and developer still want to use the modelling feature of this library.

There could be a property on the model that it is private-only/not for collaboration.

[members].map(() => makeGroupMembership(member)) would cause a `Concurrent operation` ConflictError

https://github.com/blockstack/radiks/blob/be57ef02595e5cbe44164550a86799dcb195f0cf/src/models/user-group.ts#L65

This might be caused by makeGroupMembership() saving the userGroup every time its called.

My solution for this is to sequentially call makeGroupMembership() with reduce.

[members].reduce(async (previous, member) => {
  const result = await previous;
  return [...result, await group.makeGroupMembership(member)];
}, Promise.resolve([]));

I think a better solution would be for makeGroupMembership() to take an array of usernames, iterate through them creating an Invitation for each, add them to the userGroup's members array, then save the userGroup with the updates.

Request/Question - Model count?

Still familiarizing with radiks but is it possible to get a count of a model with queries without fetching the list?

I was thinking if not then I would build a custom API and do my own query/aggregation but before I do wanted to see if a function like that could be created on the model itself. Thanks!

Calling the function `group.makeGroupMembership` throw an error

When I try to call the function group.makeGroupMembership with any username as a param (valid or not) it throws this error:

bn.js:598 Uncaught (in promise) TypeError: Cannot read property '-1' of null
    at BN.bitLength (bn.js:598)
    at Point._hasDoubles (base.js:304)
    at Point.mul (short.js:404)
    at KeyPair.getPublic (key.js:64)
    at encryptECIES (ec.js:94)
    at helpers.js:138
    at Array.forEach (<anonymous>)
    at encryptObject (helpers.js:121)
    at :3000/async http:/localhost:3000/static/js/0.chunk.js:76669

Group invitations by new users fail with `this.words is null`

Users that are not yet registered with the radiks-server (not called User.createWithCurrentUser) can't save invitations (and other models).

The error shown is this.words is null. To improve dev experience, this should be something like current user not registered on radiks-server (url). Use User.createWithCurrentUser before saving any models.

OrbitDB support in radiks

Add an abstraction layer in how the central data is been saved. We could like it is now choose for a central traditional way to get people who are new with decentralization on board.

Implement an implementation with orbitdb to store data on a distributed way.
https://github.com/orbitdb/orbit-db

orbitDB runs on top of IPFS

Later we can support DatProject, and other peer-to-peer storage solutions.

Support for Offline Mode

Radiks should support querying and saving data when offline. This would be done by creating a client-side cache of a user's data, likely using IndexedDB. When offline, changes are saved in the local DB. When the user is back online, the changes will be synced with the indexer.

Better error messages

There are a few things that are easy to get wrong when using Radiks, and the error messages are basically useless. Better error messages would go a long way in improving the DX of Radiks. For things like:

  • Calling methods when you have to be logged in, but aren't
  • Inviting a user who hasn't signed up
  • Saving a model that wasn't created by the original user
  • Using the same Radiks server database with multiple front-end apps on different domains

All of those error messages bubble up way down the stack, and are essentially cryptography error messages. Let's make them friendly and helpful.

findById only works after I save a Model

I previously saved an object with _id = "cab0cb601e13-405a-9542-25541ffd6580", when i try and findById("cab0cb601e13-405a-9542-25541ffd6580") it fails.

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
    }
}

The following code fails at Person.findById("cab0cb601e13-405a-9542-25541ffd6580");

const person = new Person();

console.log(`PERSON: ${JSON.stringify(person)}`)
//await person.save();
const results = await Person.findById("cab0cb601e13-405a-9542-25541ffd6580");
console.log(results)

The error I get is

Failed to get profile during log in! This could cause issues! SyntaxError: Unexpected token < in JSON at position 0
    at find (api.js:52)
    at async Person.fetch (model.js:186)

When I uncomment out the await person.save(); and create a new person then the findById() is able to find the person created from before:

const person = new Person();

console.log(`PERSON: ${JSON.stringify(person)}`)
await person.save();
const results = await Person.findById("cab0cb601e13-405a-9542-25541ffd6580");
console.log(results)

results finds the id

Person {schema: {…}, _id: "cab0cb601e13-405a-9542-25541ffd6580", attrs: {…}}
attrs: {likesDogs: true, _id: "cab0cb601e13-405a-9542-25541ffd6580", radiksType: "Person", createdAt: 1556233468998, updatedAt: 1556233468998, …}
schema: {name: ƒ, age: ƒ, isHuman: ƒ, likesDogs: {…}}
_id: "cab0cb601e13-405a-9542-25541ffd6580"
__proto__: Model

It seems to me that Model.save() has some side effects that I need in order for findById() to work.

Getting an error from radiks-server when trying to activate a `GroupInvitation`

When I try to activate a GroupInvitation, I get the following error.

Error: Error when saving model: 'Error when validating: No signing key is present with id: '[object Object]''

Both on the frontend and on radiks-server.

After logging some values on radiks-server, it seems that in validator.js, the signingKeyId of the models are being used. And I noticed that the signingKeyId for the GroupMembership Model is encrypted.
I checked the source code for GroupMembership at group-membership.ts and I see that the signingKeyId is indeed encrypted.

My question is, is this intentional? @hstove
If so, what might I be doing wrong?

Thanks.

What is the best way to fetch GroupInvitations?

I have met the same problem as well, my another question is how can i get my invitation from other people's userGroup

You could create a model that looks like this

{
 from: `username of admin`,
 to: `username of invitee`,
 id: `invitation id`
}

Then you could query the to field with your username.

Maybe?

Originally posted by @xanderjakeq in #45 (comment)

The above is my first thoughts. @friedger mentioned it is a privacy concern. So what the best way to find group invitations?

ID without username causes exception

User.createWithCurrentUser() causes group-membership.js:190 Uncaught (in promise) TypeError: Cannot read property 'attrs' of undefined with non-username accounts.

Ekran Resmi 2019-11-23 15 25 06

Ekran Resmi 2019-11-23 15 27 15

Tested versions: 0.2.1, 0.3.0-beta.1

Question: How to know if an object with an id exist or not

Currently if I try to find an object with a wrong id the MyModel.findById function will return an instance of MyModel so I don't really know if this id exist or not. Would be great if the function return undefined if the object is not found, what do you think?

Slow/Timeout loading issue with fetchList

Hi guys,

I'm having issues with fetchList query giving h12 Request Timeout error on Heroku.
My query is Model.fetchList({ sort: '-createdAt', limit: 500}, { decrypt: false });
To work around the issue, I set the limit : 100, but the query still takes around 20-25seconds to load which is pretty slow. The app is https://dcasso.app/, which you click on it, it takes a while to finish loading on home page.
We thought it was Heroku issue but we contacted them and they said it's because of the query code. We even paid for Heroku to hope the issue will be solved but it did not. Let me know if you face the same issue and how to fix. Thank you.

Validate usernames with every write

In the Radiks decentralization proposal, I mentioned a section around "malicious users". The gist is that Radiks should start including a username with every piece of saved data. This has many benefits, which are outlined in the forum post.

Here is the overview of how it should be implemented:

  • Whenever a model is saved, two new fields are saved in the JSON payload of every model:
    • a username attribute is attached to the JSON info for that model.
    • a jwt attribute that is the same exact authResponse token that is used during Blockstack auth.

You can get this jwt signed token by calling userSession.loadUserData().authResponseToken(). Note that this includes an encrypted appPrivateKey - but that's OK, because only the client has the transitPrivateKey that can decrypt this field.

Whenever Radiks-server is saving data from Gaia, it will validate the JWT and that it matches the username attribute. You can use the app.co-api server-side authentication reference for an existing implementation of how this is done. Fortunately, all the code required for this already exists in blockstack.js.

localStorage is not defined

While trying to create users, I am getting an error.

ReferenceError: localStorage is not defined at userGroupKeys (/Users/mahesh/projects/lettermesh-master/node_modules/radiks/lib/helpers.js:105:14) at Blog.encryptionPrivateKey (/Users/mahesh/projects/lettermesh-master/node_modules/radiks/lib/models/user-group.js:116:38) at decryptObject (/Users/mahesh/projects/lettermesh-master/node_modules/radiks/lib/helpers.js:50:34) at Blog.decrypt (/Users/mahesh/projects/lettermesh-master/node_modules/radiks/lib/model.js:197:53) at results.map.doc (/Users/mahesh/projects/lettermesh-master/node_modules/radiks/lib/model.js:66:24) at Array.map (<anonymous>) at Function.fetchList (/Users/mahesh/projects/lettermesh-master/node_modules/radiks/lib/model.js:62:40) at <anonymous> at process._tickCallback (internal/process/next_tick.js:189:7)

Bug: findById works with any argument

Currently there are two common ways to retrieve model information

  1. findById
  2. findOne

findById works with any argument regardless of if that document exists.

Code

    const radiksCheck = await User.findOne({ username }) // Tell Hank about User.findById() works with any Id
    const radiksCheck2 = await User.findById(username)
    const radiksCheck3 = await User.findById('just-random-text')

    console.log(radiksCheck, 'per find one')
    console.log(radiksCheck2, 'per find by Id')
    console.log(radiksCheck3, 'per find by Id completely random')

Output

screenshot of google chrome 3-2-19 12-25-20 pm

I assume the findById should response similarly to findOne if a document doesn't exist. Let me know otherwise!

Request: User model nested profile data grows stale

When the user initially signs into an application and gets registered via User model via
await User.createWithCurrentUser(), a document is created with some nested data via profile.

At that moment in time the profile information matches what you would normally see from a normal lookup.

However, as the user adds more apps and possibly runs into the bug of using older blockstack browsers, the apps array between a user model and his/her profile.json can be out of sync.

Example:

profile.json via lookupProfile

screenshot of google chrome 3-2-19 4-29-42 am

profile via User model

screenshot of google chrome 3-2-19 4-21-02 am

Not sure what the best workaround for this because it will be hard to tell when a user's profile apps was updated. Either way, do you think adding an additional function on the User model to update his/her profile should/could be provided? Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.