Comments (16)
Looking good! Cool to see this moving, as I've had to hack this together in our app :/
Just an initial thought: Could we merge the following methods?
Store.grantAccess()
Store.grantWriteAccess()
Something like:
Store.grantAccess('mydb', ['username1', 'username2', ...], {
read: true,
write: false
})
This means we could have other rights in the future - like security
for adding users to a db, etc. We may also be able to shorten the method grantAccess
to simply grant
, as the third parameter is defining the "access".
Also, while a Store doesn't exist, this makes sense: Store.create('mydb')
, however it feels that once you're dealing with an existing store, the syntax should be something like Store('mydb').grant(...)
Not sure if this helps?
from discussion.
I’ve replaced
store = new Store(name)
with
Store.open(name).then(function (store) {})
That way we have an async method to get a store instance in which we can prevent PouchDB from creating a database if it does not exist, so we can make sure that no database gets created without security
from discussion.
I’ve updated the README with the API, it’s work in progress:
https://github.com/hoodiehq/hoodie-store-server/tree/discussion/100/store-server-api/api
As I worked on it and made API docs and examples for every method, I’ve lost myself in a requirement we got a few times in a past to be able to set password protection for a store. What I ended up with is the idea of different "access types". By default the access type is "role", so you can grant read / write access to roles like this:
Store.grant('foo', {
role: 'acme-inc', // array sets multiple roles
access: 'read'
})
or give public read access like this
Store.grant('foo', {
access: 'read'
})
In order to check if a user with the role acme-inc
has access, you can do
Store.hasAccess('foo', {
role: 'acme-inc', // array picks any role
access: 'read'
})
That is the default behavior that Hoodie will provide, no more. The benefit is that it can be mirrored with CouchDB’s _security
settings and custom design docs (with the exception of write only)
In future, we could add APIs where plugins can register custom access types, like 'password'
, so that a call like this would be handled by the plugin
Store.grant('foo', {
type: 'password',
access: 'read',
role: 'acme-inc',
password: 'secret'
})
I also ended up calling the methods Store.grant
, Store.revoke
and Store.hasAccess
, even if access
repeats itself in the options for the latter, I think it’s better than just Store.has
and I didn’t come up with a better name yet.
from discussion.
My thinking is that the question gets answered correctly with a yes or no, either way the method behaved as expected. It would only reject if something unexpected would go wrong, like a connection error. In that regard I’d say it’s different than e.g. hoodie.store.find(id)
because it reads like I expect a document with id
to exist, and if it doesn't it’s an error
from discussion.
As mentioned on slack (edited):
I’m been keen to understand a bit more about how the PouchDB option could work. (mentioned by @janl on slack)
In the absence of what is outlined above, we have built(hacked might be a better word) something similar as we had a need to create DBs for different entities.
Our structure is something like this:
Entities have admins and employees. Admins can create and assign jobs to employees. An employee can be “upgraded” to an admin.
So our Hoodie/CouchDB structure becomes:
When a entity is created, I add this new entity to a “entities” db, then create two new dbs specific to that entity - entity/12345
and entity/12345/admin
. The latter because there is certain info I don’t want employees having access to, and I couldn’t be bothered with filtered replication for this task (possibly the wrong move, not sure yet). I then simply add a users’ role to the entities db based on their role in the entity. So if a user is an “employee”, I only add their id to the entity/12345
db. Now when an admin adds a job to this db it gets synced to the user, etc. So what is outlined above in theory helps with a large portion of our process.
There are a number of other solutions I considered, too. One option was to replicate individual docs from the entity db to the users personal db. This solution would be more efficient longer term, but has a slightly more complicated setup. And I think that regardless of these two options, I wanted to have a entity/12345
db so that all information for a given entity was stored in a common place.
Maybe this situation helps expand on the concept a little?
from discussion.
It's worth pointing out that if I went with my other option I mentioned above (per-doc replication to a users' db) It would(may) remove the need to grant/revoke access to a db, as the data would be filtered and synced based on some form of server-side logic.
So if I went down this path, I'd need some logic in the background to make it easy to assign a type of data (most likely a filter function) to a users' db.
I also avoided this example as we may in the future allow a user to belong to multiple entities... meaning I didn't want to deal with changing a users' db structure etc. But that's me getting too deep into our business needs, not hoodie's needs ;)
from discussion.
@gr2m think that's a nicer way to separate the factory from the constructor/use of the store - think it was slightly ambiguous before on how to differentiate one store from another etc.
from discussion.
If we have Store.grant()
and Store.revoke()
methods to grant / revoke access to / from a user, what should we call the method with which we can check if a user has the required access for an operation?
Maybe Store.has()
, or in that case Store.hasAccess()
? E.g.
Store.hasAccess(dbName, {read: 'id:123'})
from discussion.
Hmmm good question. '.has' is consistent, but ambiguous in this context... you could use '.can' (I.e. 'Store.can({read:[]})'), but doesn't exactly resolve the ambiguity.
Maybe my idea of removing the word access has proven to not work now?
from discussion.
Maybe my idea of removing the word access has proven to not work now?
Yeah feels like it right now. But this is a process, we’ll come up with something good at the end. I’ll move forward with grantAccess
/ revokeAccess
/ hasAccess
for now and see how it feels
from discussion.
Totally, sounds good to me!
from discussion.
The current solution creates a meta database to keep track of all databases, as this is not something that PouchDB provides by default. There is https://github.com/nolanlawson/pouchdb-all-dbs which does the same but in more complicated way, as it most be compatible with the synchronous new PouchDB(name)
while we could agree on having an asynchronous Store.open
method, which can be async and can do all kind of checks before returning a store API instance.
In my current implementation I also store security in that database, which has the benefit that we can query what databases a user / a role has access to in future. If the backend is CouchDB, we can additionally keep CouchDB’s /_security
in sync for double security
from discussion.
I implemented all but Store.replication
API and the events, let me know what you think 💭
from discussion.
I see that store.exists
resolves with a boolean value stating if the store exists or not. I'm not sure on the answer, but should the promise not resolve if it does exist, and reject if the store doesn't exist? I suppose the user needs to know if there's another reason for rejection, as they may be trying to create if it doesn't exist... Just thought I'd ask?
from discussion.
the PR is ready for review: hoodiehq/hoodie-store-server#45
from discussion.
we have https://github.com/hoodiehq/hoodie-store-server-api now :)
from discussion.
Related Issues (20)
- Changelog? HOT 2
- [maintainers RFC] replace lgtm.co integration with requiring reviews HOT 5
- tasks: provide user context
- all users have access to all data and a central db HOT 1
- [RFC] merge UI from @hoodie/store & @hoodie/account into hoodie HOT 4
- Store: Hoodie properties added to documents HOT 19
- scoped stores and the type property HOT 21
- Move configuration from ./package.json to ./hoodie/config.js HOT 7
- admin accounts and server secret HOT 3
- 📖👀 Let’s use readthedocs.org for Hoodie HOT 4
- Implementation of Web App with Data Sharing Requirement HOT 4
- Rails Girls Summer of Code 2017 submission 🚂👩🏻💻👩🏾💻✨ HOT 4
- Google Summer of Code submission HOT 2
- Change our Code of Conduct HOT 6
- (client) remove hoodie.ready.then(...) HOT 2
- Overlap with SuperLogin HOT 1
- Hook or event when local database is created HOT 7
- @hoodie/api HOT 6
- Would love to be part of the organization and contribute towards it. HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from discussion.