Giter Site home page Giter Site logo

smallbets / userbase Goto Github PK

View Code? Open in Web Editor NEW
2.2K 34.0 123.0 14.12 MB

Create secure and private web apps using only static JavaScript, HTML, and CSS.

Home Page: https://userbase.com

License: MIT License

JavaScript 91.84% HTML 2.08% CSS 1.13% Shell 0.15% TypeScript 0.94% Makefile 0.17% C 3.23% Java 0.21% Objective-C 0.26%
database end-to-end-encryption backend-as-a-service frontend userbase privacy

userbase's People

Contributors

dependabot[bot] avatar dvassallo avatar fubinator avatar j-berman avatar jneterer avatar mastrolinux avatar mhxbe avatar raae avatar shamblesides avatar sullis avatar tim-lyon avatar yuya-fujimoto 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  avatar  avatar  avatar  avatar

Watchers

 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

userbase's Issues

Uncaught SyntaxError on openDatabase

I get an Uncaught SyntaxError: Unexpected token ',' error when I do…

userbase.openDatabase({'…', function(items) {…}})

But not when I replace it with…

userbase.openDatabase({databaseName: '…', changeHandler: function(items) {…}})

(I'm using https://sdk.userbase.com/1/userbase.js.)

Excessive Client Package Size

Userbase looks promising and definitely satisfies a need in front-end development.

However, I noticed the client library is massive: ~70K gzipped. Much of which comes from @babel/runtime-corejs3.

In general, client libraries don't ship polyfills. Instead, they note browser support in the README and let consumers polyfill as needed. Not reason every consumer should have to bear the burden of @babel/runtime-corejs3.

Likewise with axios. It's not much compared to @babel/runtime-corejs3, but 4K isn't nothing. And it's certainly not carrying its own weight given it's used only in api/auth.js. Consider using fetch directly and—again—letting the consumer polyfill as needed.

Perhaps all of this known and temporary. If so, please disregard.

Add unencrypted metadata to a database

Sometimes it could be useful, similar to user profiles, to store unencrypted meta data in a database. An example would be a self implemented 1-n relation where the n databases have different user permissions.

A real world example would be:
There are organizations and each organization has different users with different permissions. However, it is possible for users to be part of multiple organizations.
If I now want to create teams within the organization, which include different users of the organization with different permissions, I have a problem.

Now, to get the teams of a user within an organization, I would either have to choose database names that contain the organization, or I would have to open ALL team databases of a user and open a team entry to filter out the right teams. Since database names are limited to 50 characters, it is not easy to ensure collision free names in the first approach. With the second approach I see serious performance issues in the long run.

One idea to solve this would be to store the organization ID as unencrypted meta data, so that you can easily filter for this meta data with getDatabases() without opening every database first.

Track file upload progress

When uploading large files, it would be useful to be able to track the progress of the upload (especially for progress bars). Maybe the uploadFile function could get a handler which returns the current progress in certain intervals.

Example API:

const exampleFile = new File(['example'], 'example.txt', { type: 'text/plain' })

userbase.uploadFile({
  databaseName: 'example-database-name',
  itemId: 'example-id',
  file: exampleFile,
  progressHandler: (bytesTransferred) => console.log(bytesTransferred / exampleFile.size) // => would log percentage
}).then(() => {
  // file stored durably
}).catch((e) => console.error(e))

Generic state support

User Story
As a developer, I want to be able to store data that is not user specific and is used across my application.

Example
A coding interview platform.

  • User specific data: user profile
  • Generic data: the list of available coding challenges.

ServiceUnavailable after database sharer is deleted

To reproduce

  • Create user 1
  • Create user 2
  • User 1 creates database and shares it with user 2
  • Permanently delete user 1 in the admin panel.
  • User 2 tries userbase.getDatabases() but it fails with a ServiceUnavailable error.

Revoke own access to shared database

It might be useful to allow users to revoke their own database access from shared databases. A scenario for this would be: A user can be part of several teams (each team has one database) and wants to leave one team. In this case, he would have to tell a user with resharing permissions that he wants to leave the team.

WebSocket error on signIn in Firefox

In Firefox, invoking the signIn method leads to a WebSocket error:

Screenshot 2020-06-28 at 13 30 59

The same code works in Chrome and Safari.

This happens with a create-react-app project, on http://localhost:3000

Versions used:
userbase-js 2.0.0
Firefox Developer Edition 78.0b9
Firefox 77.0.1

Can't update password

I keep getting a “Incorrect password” error message when I try to update my password in the admin page. I even tried to replicate the format used in the temporary password.

Screen Shot 2020-03-05 at 12 30 10 PM

Screen Shot 2020-03-05 at 12 32 28 PM

User logout after trying to change password

When I try to change password with

userbase.updateUser({
  currentPassword: 'example-password',
  newPassword: 'example-new-password'
})

If I enter the right currentPassword, it works well and It changes the password with the new one.

But if I enter the wrong password i receive this error "CurrentPasswordIncorrect", and it seems that it terminates the current session. If I retry to do another request I receive the error: UserNotSignedIn and I need to login again.

Userbase doesn't work with Vite / Rollup

When trying to start a fresh App with userbase-js as a dependency, I get the following error from Vite:
Screenshot 2020-09-01 at 6 17 29 PM

When starting my app with userbase-js as a dev dependency:
import userbase from 'userbase-js'; or import * as userbase from 'userbase-js';
Error Screenshot

import userbase from '../../node_modules/userbase-js/dist/userbase.js';
Error Screenshot 2

import * as userbase from '../../node_modules/userbase-js/dist/userbase.js';
Error screenshot 3

I found a reference in Vite issue #728, but none of the fixes there seemed to help.

I've been stuck on this for days now, and I don't seem to be getting any closer to figuring it out. Any advice would be greatly appreciated!

Add shared data to openDatabase

I apologize if this functionally is already included, I just haven't found it in the documentation.

Issue

At the moment, the openDatabase response does not provide any information on whether the database has been shared, who it's shared with, who owns it, etc.

Request

Similar to getDatabases, could you return the same data for openDatabase? This data would be:

  • isOwner
  • readOnly
  • resharingAllowed
  • receivedFromUsername
  • users

Choose a more searchable name

This might be a shot in the dark, but I have had a hard time searching for userbase as a project name. It gives many, many unrelated results on google 😉

So I don't know whether you would consider changing to a less generic project name, but that would help people trying to do research or find docs quickly.

TypeScript: optional parameters (databaseName & databaseId)

Hi,

I've got a question/suggestion about the provided types.
10 functions require at least databaseName or databaseId
https://github.com/smallbets/userbase/blob/master/src/userbase-js/types/index.d.ts#L123-L145

The Problem
They're both optional parameters so TypeScript doesn't complain when none of them are provided.

Possible solution
I was thinking about something like this:

type databaseNameOrId = ({ databaseId: string } | { databaseName: string });

export interface Userbase {
  insertItem(
    params: databaseNameOrId & { item: any; itemId?: string }
  ): Promise<void>;
}

Personally, I think this syntax is acceptable. However, the type-error that TypeScript generates when none of both parameters are provided is somewhat noisy & possibly unclear.

Argument of type '{ item: string; }' is not assignable to parameter of type '({ databaseId: string; } & { item: any; itemId?: string; }) | ({ databaseName: string; } & { item: any; itemId?: string; })'.
Type '{ item: string; }' is not assignable to type '{ databaseName: string; } & { item: any; itemId?: string; }'.
Property 'databaseName' is missing in type '{ item: string; }' but required in type '{ databaseName: string; }'.

I've made an example repository here where you can try it for yourselves: https://github.com/mhxbe/userbase-database-types
I hope there's a better way of typing this, but I'm not sure.

Suggestions/improvements are welcome.

New Admin API Endpoint: List Database Users

curl 'https://v1.userbase.com/v1/admin/databases/$DATABASE_ID/users?nextPageToken=$NEXT_PAGE_TOKEN' \
  -XGET \
  -H 'Authorization: Bearer $ACCESS_TOKEN'

Result

  • nextPageToken [string]
  • users [array]
    • userId
    • readOnly
    • isOwner
    • resharingAllowed

See here for the other endpoints.

Singup Testing Failed

AssertionError: expected '' to have a property 'userbase'

Because this error occurred during a 'before each' hook we are skipping the remaining tests in the current suite: 'Signup Testing'

Enable user to delete all data and create new password

Overview

As proposed by @alexcnichols in #59, in addition to Userbase's current forgot password mechanism (#103), it would be a nice feature to allow users who lose their password to delete all their data and create a new password.

Proposed Implementation

  • A user must have an email saved on their account.
  • A developer can call a new Userbase SDK function resetAccount({ username }) or something similar, which sends a message to the user's email.
  • The message will contain a temporary reset password that will expire after 24 hours.
  • The user simply has to provide that value as their password to signIn().
  • If the user provides the correct reset password to signIn(), Userbase will mark all the user's old data for deletion (to be deleted asynchronously in the nightly purge) then allow the user to sign in normally (& create a new password).

Note, the user's plaintext data (profile + protectedProfile) would not be deleted.

Password-Manager error

On every delete operation on items from the to-do example the password manager is triggered (tested 1password on mac on my laptop). A prompt is shown to store the password.

How can i insert nested data into the database?

Hi, not really an issue but a question.

I want to build an app where a coach can write progress reports for his clients, and I am absolutely not sure how to model this.

In #142 i've read that it is totally ok, to have more than one database.

Does this mean, in my case, i can create two databases - one for the clients, one for the progress reports - and connect them somehow?

As far as i understand the insertItem documentation, it's possible to specify only one database at a time. So my Workflow would be, to have some kind of a details page for every client where i can create the progress reports?

Thanks in advance for your help!

Feature request: additional database permissions option, insertOnly

In addition to the current two flags, readOnly and resharingAllowed, I've found myself wanting a third option, where an invited user could insert new documents, but could only update or delete documents that they themselves inserted.

This might be a new property like insertOnly: true or it might be some non-boolean value for readOnly, like { "readOnly": "others" }

`openDatabase` Issues + Nit

1. Opening database removes existing handler

I guess this behavior is intentional, but it's not obvious. I'd be happy to document it.

2. changeHandler is called on database open

It's also not obvious that changeHandler would behave this way, and it contradicts the documentation:

A callback that gets invoked when the database gets modified.

A more natural behavior might be to skip the initial call of changeHandler and instead resolve openDatabase with the data:

const initial = await userbase.openDatabase({
  databaseName: '',
  changeHandler() {},
});

3. Unable to unsubscribe from changeHandler or close database

A wee memory leak. And it's a bit cumbersome for the user, who has maintain some state to key off of in changeHandler to determine whether or not to process the change.

4. Nit: Options are unnecessarily verbose

  • databaseName -> name
  • changeHandler -> onChange

Unable to Delete Database

It doesn't look like there's an SDK method for deleting a database—only one for deleting individual items in batches of ten.

I'm building an RSS reader and using Userbase to sync feed subscriptions and unread articles. I thought I'd create a feeds database and store each feed as an item in it. Like so:

userbase.insertItem({
  databaseName: 'feeds',
  item: {
    url: feed.url,
    unread: [{
      date: article.date,
      url: article.url,
    }],
  },
  itemId: md5(feed.url), // MD5: 100 character limit
})

However, it's not uncommon for a user to let unread articles pile up, leading to tens or hundreds of unread. It makes sense to limit unread articles somewhat—perhaps to the most recent hundred. But the 10 KB limit on a databases items prevents me from storing even 50 unread.

So I'm instead creating a database per feed, while storing each unread as an individual item. I never run up against the 10 KB limit for items, of course. But it's cumbersome to clear out a feed database in batches of ten (rate-limited, of course) after a user has unsubscribed from a feed. I'd like to simply delete the database and be done.

I also wonder. Is creating a database per feed even advisable? It's the only way I can see an RSS reader existing given the 10 KB item limit. But is there a hard limit on databases per user? Because I can easily imagine users who are subscribed to a couple hundred feeds. If there is a limit, some error messaging would be helpful.

Anywho, thanks for making Userbase.

security issue

If somebody has access your server and modifies the client's javascript, can steal the users key.

Error is thrown when deleting a user that had shared db access

I don't know if this is intentional, but when I delete a user in the admin interface who previously had a shared database, getDatabases throws an exception when logged in as the database owner:

Uncaught (in promise) ServiceUnavailable: Service unavailable.
    at _parseGenericErrors (webpack-internal:///./node_modules/userbase-js/lib/db.js:49:13)
    at Object.getDatabases (webpack-internal:///./node_modules/userbase-js/lib/db.js:1660:7)

Note: This happens as soon as I permanently delete a user in the interface. It still works if the deletion is pending.

[docs] `changeHandler` and `updateUserHandler`

These two behave slightly different.

updateHandler gets items as the argument, while updateUserHandler gets an object (with user as the attribute) as the argument. Might be messing up my terms here, but it would therefore be beneficial with an example also on the init documentation page similar to the one for openDatabase:

This exists:

changeHandler: function (items) {
    // update your application state with the database items
}

This should be added:

updateUserHandler: function ({user}) {
    // update your application state with the updated user
}

"Forgot password?"

As part of the early preview, the primary reservation I've had is around the demand put on end users to retain the decryption key.

I was happy to see this week in the FAQ that the method of storing the key was enhanced to generate based on the user's password and store on the Userbase servers. That solves some complexity and removes the dependency to be locked into a single browser's storage... from what I can tell, this means users can roam between between browsers and devices and still login.

The demand on the end user to never lose their password remains though.

  1. To what extent to you see this as an adoption blocker? Maybe there are use cases for certain customers where this isn't as much of an issue.
  2. Any ideas for how to securely help end users recover from a lost password?

At the very least I could imagine a feature to "Delete all data and create new password". 🤷‍♂

Great work so far! Looking forward to the upcoming public launch. 🚀 🎉

SignUp Flow

While signing up, after pressing the signup button, it did not move to the login page or logged me in.
Instead it kept showing the loader, i waited for 30 seconds.
But, the sign up was successful.
(Ubuntu, Chrome).

Also I did not get the key.

window.crypto.subtle being undefined on chrome

  • Version 80.0.3987.132 (Official Build) (64-bit)
  • Darwin mbp.local 16.7.0 Darwin Kernel Version 16.7.0: Sun Jun 2 20:26:31 PDT 2019; root:xnu-3789.73.50~1/RELEASE_X86_64 x86_64

Ugliest_To-Do

and I get ServiceUnavailable.

Same code works on Firefox Version 73.0.1.

A couple of bugs are detected by SonarCloud that should by fixed IMHO

Hello,

I scanned your project with SonarCloud and I realized there are 2 categories of bugs detected that you should look at:

The problem is located on src/userbase-server/app.js

image

If !app is true, it means app is undefined so app['app-id'] is also undefined and will fail at runtime.

Regards
Alex

Pagination and data size limits

I've been playing with Userbase over the last few days and I have a few doubts regarding how large amounts of data is handled.

Suppose a user's database has over 100mb data. As far as I'm aware, the changeHandler picks up all items available in the database. Does this mean all 100mb will get downloaded on the client side at some point?

If that is the case, it would be nice to have pagination support. It could be a new endpoint called getDatabasePage with parameters "pageSize", "pageNumber" and "databaseName".

openDatabase can have a parameter "doNotFetch" to avoid downloading all that data.

A few alternative approaches
These are some approaches I've thought of that wouldn't require a new endpoint but will need some client side coding to manage.

(1) Pagination by date ranges
A cheeky alternative to this would be to create a new database every week / month per user depending on the amount of data the app is going to generate and to fetch those databases on-demand. Pagination by date ranges essentially.

(2) Pagination by total items
Create a new database for every X items, depending on item size and keep a database counter in the user's profile.

Please let me know if my understanding of Userbase is wrong or if I'm missing something important.

Thanks!

Feature request: fetch individual item history

Proposed usage:

userbase.itemHistory({ databaseName, itemId }).then(revisions => {
  for (const revision of revisions) {
    const { item, username, userDeleted, timestamp } = revision
    // maybe file stuff too? Not sure if old files are stored permanently
  }
})

Maybe would always be fetched from transaction log rather than the bundle.

localStorage session expires too early

To reproduce:

  1. Log in with rememberMe: 'local'. I said to remember me for 1 year to test with.
  2. Check localStorage; userbaseCurrentSession will have a correct expirationDate
  3. Refresh the page and wait for userbase to initialize
  4. Check localStorage; userbaseCurrentSession will now have an expirationDate that is too early
  5. This causes the session to expire too early!

Allow some databases to open without payment

I would like to capture and save some data from the user before sending them to payment.

It could be a setting in admin that lets us add database names that should not be paywalled.

Transfer ownership of a database

Currently, according to the docs, any database of a user is deleted as soon as he deletes his account. This also happens with shared databases. Would it be possible to implement a functionality to change the owner of a database to prevent this?

Question: Feasible to use API Gateway Web Sockets + Lambda Instead of EC2?

Thank you for making this OSS. I've been reading the code and it's a great example of how to create a multi tenant SaaS product. I wanted to understand for my own purposes if this could be deployed in a self-hosted manner with more of a serverless / pay-per-use approach. My thought was API Gateway websockets + lambda. I understand why it may not work for your hosted offering you run due to limits/quotas/latency, but assuming those are not a concern/blocker for self-hosting, are there any technical challenges to go with this approach? Long-running process(es) (lambda limits - time, memory), preserving e2e encryption, some other security aspect, etc.?

If not, I'd look to build out and contribute back here.

Thanks in advance for any help!

Remember me forever

My user's have been asking me why they have to log in again all the time.
They want it to be more "app like" and are not to worried about someone accessing their phones.

Could it be possible to get a remember me until I explicitly sign out.
Or is this already possible and I have just missed the docs.

Whitelist Domains for Userbase Apps

Problem Statement

At this time, any individual can copy the app id from the application code and use that app id. Although the app id can't be used to access user information, someone could still use that app id to create and deploy a web app that uses it.

Proposal

Have the ability to list domains the app id can be used on. I don't believe this is a major security concern and needs addressed right now, but I do think it would be good at some point to put in place as another item to check off with regards to better security/best practices.

Thank you Userbase for all the hard work you do! And for this awesome service!

userbase.getDatabases() always fails when the user has 24+ databases

When using the JavaScript SDK, calling userbase.getDatabases() seems to send a "GetDatabaseUsers" message through the websocket for every single database that the user has access to. Because they are sent all at once, this trips the websocket server's rate limit of 25 messages per second. The result is a confusing ServiceUnavailable error with a TooManyRequests error inside.

REQUEST: Master Userbase for multi WordPress sites

Wow, At first I wasn't for sure if I understood correctly what userbase was... until I started reading the DOCS and the code examples and now I am very excited to say:

I THINK YOU GUYS MIGHT HAVE SOLVED A MULTI LOGIN FOR WORDPRESS!

Now I know this app is made for static sites specifically, but I just had to offer a suggestion and request.

Is it possible that if this is tied to a Wordpress site as the main sign up, when I user signs up in Wordpress they will see a userbase signup screen... After signing up, userbase pushes to that Wordpress site's USERS WP REST API endpoint to update the users of a family of WP sites user database tables?

For example, To create a User in WP:
https://developer.wordpress.org/rest-api/reference/users/#create-a-user

It respectfully UPDATES, DELETES users across multi spectrums using userbase as the Master commando!
https://developer.wordpress.org/rest-api/reference/users/#update-a-user
https://developer.wordpress.org/rest-api/reference/users/#delete-a-user

This seems like a simple feat but will be powerful!!!

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.