Code Monkey home page Code Monkey logo

frame's Introduction

No longer maintained

Boilerplates can be a huge time sink to maintain and I've decieded to archive this project.

Thanks for your interest in my projects.


Frame

A user system API starter. Bring your own front-end.

Build Status Dependency Status devDependency Status

Features

  • Login system with forgot password and reset password
  • Abusive login attempt detection
  • User roles for accounts and admins
  • Admins only notes and status history for accounts
  • Admin groups with shared permissions
  • Admin level permissions that override group permissions

Technology

Frame is built with the hapi framework. We're using MongoDB as a data store.

Bring your own front-end

Frame is only a restful JSON API. If you'd like a ready made front-end, checkout Aqua. Or better yet, fork this repo and build one on top of Frame.

Live demo

url username password
https://getframe.herokuapp.com/ root root
https://getframe.herokuapp.com/documentation

Postman is a great tool for testing and developing APIs. See the wiki for details on how to login.

Requirements

You need Node.js >=8.x and you'll need a MongoDB >=2.6 server running.

Installation

$ git clone https://github.com/jedireza/frame.git
$ cd frame
$ npm install

Configuration

Simply edit config.js. The configuration uses confidence which makes it easy to manage configuration settings across environments. Don't store secrets in this file or commit them to your repository.

Instead, access secrets via environment variables. We use dotenv to help make setting local environment variables easy (not to be used in production).

Simply copy .env-sample to .env and edit as needed. Don't commit .env to your repository.

First time setup

WARNING: This will clear all data in the following MongoDB collections if they exist: accounts, adminGroups, admins, authAttempts, sessions, statuses, and users.

$ npm run first-time-setup

# > [email protected] first-time-setup /home/jedireza/projects/frame
# > node first-time-setup.js

# MongoDB URL: (mongodb://localhost:27017/frame)
# Root user email: [email protected]
# Root user password:
# Setup complete.

Running the app

$ npm start

# > [email protected] start /home/jedireza/projects/frame
# > ./node_modules/nodemon/bin/nodemon.js -e js,md server

# 09 Sep 03:47:15 - [nodemon] v1.10.2
# ...

Now you should be able to point your browser to http://127.0.0.1:9000/ and see the welcome message.

nodemon watches for changes in server code and restarts the app automatically.

With the debugger

$ npm run inspect

# > [email protected] inspect /home/jedireza/projects/frame
# > nodemon --inspect -e js,md server.js

# [nodemon] 1.14.12
# [nodemon] to restart at any time, enter `rs`
# [nodemon] watching: *.*
# [nodemon] starting `node --inspect server.js`
# Debugger listening on ws://127.0.0.1:9229/3d706d9a-b3e0-4fc6-b64e-e7968b7f94d0
# For help see https://nodejs.org/en/docs/inspector
# 180203/193534.071, [log,info,mongodb] data: HapiMongoModels: successfully connected to the db.
# 180203/193534.127, [log,info,mongodb] data: HapiMongoModels: finished processing auto indexes.
# Server started on port 9000

Once started with the debuger you can open Google Chrome and go to chrome://inspect. See https://nodejs.org/en/docs/inspector/ for more details.

Running in production

$ node server.js

Unlike $ npm start this doesn't watch for file changes. Also be sure to set these environment variables in your production environment:

  • NODE_ENV=production - This is important for many different optimizations.
  • NPM_CONFIG_PRODUCTION=false - This tells $ npm install to not skip installing devDependencies, which we may need to run the first time setup script.

Have a question?

Any issues or questions (no matter how basic), open an issue. Please take the initiative to read relevant documentation and be pro-active with debugging.

Want to contribute?

Contributions are welcome. If you're changing something non-trivial, you may want to submit an issue before creating a large pull request.

Running tests

Lab is part of the hapi ecosystem and what we use to write all of our tests.

$ npm test

# > [email protected] test /home/jedireza/projects/frame
# > lab -c -L

#  ..................................................
#  ..................................................
#  ..................................................
#  ..............

# 164 tests complete
# Test duration: 14028 ms
# No global variable leaks detected
# Coverage: 100.00%
# Linting results: No issues

Targeted tests

If you'd like to run a specific test or subset of tests you can use the test-server npm script.

You specificy the path(s) via the TEST_TARGET environment variable like:

$ TEST_TARGET=test/server/web/main.js npm run test-server

License

MIT

Don't forget

What you build with Frame is more important than Frame.

frame's People

Contributors

blaircooper avatar bmgdev avatar fishmongr avatar gregfrasco avatar ivanph avatar jedireza avatar kole avatar richardzyx avatar robbyoconnor 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  avatar

frame's Issues

Fix bug in PUT /accounts/{id}

On Account Update request, the name object will be overwritten by the firstname.

Payload:

payload: {
  name: Joi.object().keys({
    first: Joi.string().required(),
    middle: Joi.string().allow(''),
    last: Joi.string().required()
  }).required()
}

Update:

var update = {

  $set: {
    name: request.payload.name.first // must be 'request.payload.name'
  }
};

Line

Problems with permissions and groups for Admins

Hey,
I'm about to add permissions and groups to ngFrame, but there is one problem.

In Drywall, according to the schemas you have an Array of groups and permissions.
In Frame you can push whatever to permissions and the groups are not an array after all.
I also don't see a way to update/delete permissions.

So what I actually want:

/admins/{id}/permissions:

A way to delete and update (update for permit true/false).
A solid schema, so I cant override the permission array and add any attributes.

/admins/{id}/groups:

Should be an array, is an object and can also be overridden (this could be anything groups: Joi.object().required()).

If you got any questions ask me any time :)

Setup.js failing

Running setup.js seems to be failing when calling the BaseModel.connect function. The url does not appear to be getting passed into haps-mongo-models property. Using the default for the mongodb url.

/Users/chad/Documents/Development/example-code/frame/node_modules/mongodb/lib/mongodb/connection/url_parser.js:14
  if(url.indexOf("mongodb://") != 0)
         ^
TypeError: Cannot call method 'indexOf' of undefined
    at exports.parse (/Users/chad/Documents/Development/example-code/frame/node_modules/mongodb/lib/mongodb/connection/url_parser.js:14:10)
    at Function.MongoClient.connect (/Users/chad/Documents/Development/example-code/frame/node_modules/mongodb/lib/mongodb/mongo_client.js:164:16)
    at Function.BaseModel.connect (/Users/chad/Documents/Development/example-code/frame/node_modules/hapi-mongo-models/lib/base-model.js:16:25)
    at Array.Async.auto.connect [as 0] (/Users/chad/Documents/Development/example-code/frame/setup.js:121:27)
    at /Users/chad/Documents/Development/example-code/frame/node_modules/async/lib/async.js:487:38
    at Array.forEach (native)
    at _each (/Users/chad/Documents/Development/example-code/frame/node_modules/async/lib/async.js:46:24)
    at Object.async.auto (/Users/chad/Documents/Development/example-code/frame/node_modules/async/lib/async.js:458:9)
    at Array.Async.auto.setupRootUser [as 1] (/Users/chad/Documents/

logout doesn't work

I branched from master [2cf0d23] and logout doesn't work. I see that the logout code looks for 'username' in sessions but the key, i believe, should be 'userId' and the value shouldn't be the username it should be userId: user._id.toString()

Whats with the session being created on signup with the userId set to the username?

hapi-auth-basic vs hapi-auth-cookie

Just a question.

I can see that hapi-auth-basic and hapi-auth-cookie provide very similar security level as you generate password per session for auth-basic.

Also I see advantage that session model can be easily extended for additional data that are useful to keep in session, no need to use https://github.com/hapijs/yar for session data.

So basically just wondering what was your thought process to go for basic-authentication. I can also see using auth-basic in frame as beneficial :-).. just basically trying to make sure that I don't miss something as I considered hapi-auth-cookie as more common and secure option before.

Why are (most) endpoints pluralized?

I'm starting out trying to be a Legit Programmer, and I read some tutorials on how to design REST apis.

My question, Why are most of the endpoints pluralized? I get the impression that there aren't hard and fast rules, but it seems like people consider singular noun endpoints as the "right" way to do it. I'm thinking about reformulating your endpoints as singular nouns. I can send you a PR if you want for this.

More important, I'd like to hear your rationale behind this design decision.

Extend login by responding with user role

Can I access the user role from somewhere, or can I add it to the login response object and ask for a pull request. Its hard to guess what the user is permitted to.

Rationale for indentation style in Models, and elsewhere?

Hi jedireza, thanks for building frame. I dig it!

I wanted to ask you, What's your rationale for the eccentric indentation style for stuff in the models folder, and functions in general? Everything is flattened, like statements inside functions and stuff... they're vertically aligned with the function definition, etc.

I like the stuff you make, and thought you may have some wisdom on why you do this.

User and Account

I can see from the code, when you create a user, there is also an account that is created within the user model. The full name is stored in account and the username is stored in user.

What is the intention of the separation? It appears that a user would have multiple accounts, so say I want to add twitter/facebook logins, would the best way be to add these as accounts to the user?

Generally, when extending the codebase, what would you put in User and what would you put in Account?

Would love to have some documentation to clear this up =)

Test Fails

Hi,

After upgrading to the latest version of frame (v3.1.1) i'm having an issue when running npm test any ideas what this could be?

Failed tests:

  3) App it composes a server:

      Unknown authentication strategy: simple in path: /api/users

Comments/description in the code

I wanted to ask that you might add a general description to the top of the documents about what they do and control flow to and from the documents. I'm new to the industry and we are using hapi for a webservice project but i would like more information to help the learning process. Especially considering this is an example posted directly on Hapi's site.

Account is created but 500 error returned because SMTP failure

On /api/signup if nodemailer call fails to make the outbound mail send call the client gets a 500 error but the account was created.

Since the account was created this should return a successful response.

Suppose it gets tricky if you are requiring email confirmation... if the mailer fails should you NOT create and throw a generic error?

Why "admin role" for status updates?

Also, kinda related, I don't understand the meaning behind your usage of the word "pivot."

I saw how it's used in your aqua framework, and I assume it's the identical idea in frame. I get what it does, but the feature comes off a little weird to me. Can you elaborate on it?

async v/s promises

the code with promises is far more readable than with async. if we do not lose anything by using promises, move to promises.

logging

hapi uses good. would be good to have default file and console loggers as part of the build.

thanks

Single server by default

To keep new projects simple it's probably best to just create one server. In order to do that effectively, we also need to configure a base path for the api plugins.

successful link/unlink handlers return empty

hey jedireza,
i think the link/unlink handlers stated below don't return the result of the successful operation. they return just empty. if you wanted to return the updated account

reply(results.account[0]) 

should be

reply(results.account); 

---
server.route({
    method: 'DELETE',
    path: options.basePath + '/accounts/{id}/user',

server.route({
    method: 'PUT',
    path: options.basePath + '/accounts/{id}/user',

Investigate using hapi's `auth.scope`

Instead of using:

plugin.route({
    method: 'GET',
    path: '/route',
    config: {
        auth: 'simple',
        pre: [
            authPlugin.preware.ensureUserRole('admin'), // changing this
            authPlugin.preware.ensureAdminGroup('root')
        ]
    },
    handler: function (request, reply) {

        reply(...);
    }
});

we could use something like:

plugin.route({
    method: 'GET',
    path: '/route',
    config: {
        auth: {
            strategy: 'simple',
            scope: 'admin' // to this
        },
        pre: [
            authPlugin.preware.ensureAdminGroup('root')
        ]
    },
    handler: function (request, reply) {

        reply(...);
    }
});

For more details on scope see: http://hapijs.com/api#serverrouteoptions

Add default sort option to api endpoints

These api endpoints need a default sort option during query validation:

server/api/accounts.js
server/api/admin-groups.js
server/api/admins.js
server/api/auth-attempts.js
server/api/sessions.js
server/api/statuses.js
server/api/users.js

Example:

validate: {
    query: {
        // ...
        sort: Joi.string().default('_id'),
        // ...
    }
},

can not run setup

Hello,

when i run "npm run setup" under C:\dev\js\frame that is cloned from github on 14-04-2015, i get the following error. Please advise and many thanks in advance.

0 info it worked if it ends with ok
1 verbose cli [ 'c:\\Program Files\\nodejs\\node.exe',
1 verbose cli   'c:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js',
1 verbose cli   'run',
1 verbose cli   'setup' ]
2 info using [email protected]
3 info using [email protected]
4 verbose run-script [ 'presetup', 'setup', 'postsetup' ]
5 info presetup [email protected]
6 info setup [email protected]
7 verbose unsafe-perm in lifecycle true
8 info [email protected] Failed to exec setup script
9 error [email protected] setup: `./setup.js`
9 error Exit status 1
10 error Failed at the [email protected] setup script.
10 error This is most likely a problem with the frame package,
10 error not with npm itself.
10 error Tell the author that this fails on your system:
10 error     ./setup.js
10 error You can get their info via:
10 error     npm owner ls frame
10 error There is likely additional logging output above.
11 error System Windows_NT 6.2.9200
12 error command "c:\\Program Files\\nodejs\\node.exe" "c:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "run" "setup"
13 error cwd c:\dev\js\frame
14 error node -v v0.10.35
15 error npm -v 1.4.28
16 error code ELIFECYCLE
17 verbose exit [ 1, true ]

Things not transferred from Drywall

Just a list of things I have not addressed that Drywall has:

  • account signup email verification
  • helmet helmet(app);
  • csrf app.use(csrf({ cookie: { signed: true } }));
  • compression app.use(require('compression')());
  • social signup and login (via Passport.js)

Deplay to heroku

What should I deploy to heroku? which file should be run first
what changes should I do in the configs
Should I run the setup with with params for the production environment ?
which file should i call in "web: node index.js"?

Thanks
Amit Shvil

starting the server fails due to missing mongodb url in hapi-mongo-models

hey jedireza,
great project! in the latest version starting the server fails due to missing mongodb url in hapi-mongo-models:

TypeError: Cannot read property 'url' of undefined
at Function.BaseModel.connect (frame/node_modules/hapi-mongo-models/lib/base-model.js:16:39)

the mongodb object is undefined at frame/node_modules/hapi-mongo-models/index.js:16:15

BaseModel.connect(mongodb, function (err, db) {

if i hardcode it here, everything works like expected

Documentation for Auth Interface

Since Frame has no example front end like Drywall, I need some specs I can work against.

I have trouble getting the basic auth working. What does the simple auth expect from the user/front end.

The auth informations in hapi.js:

request.auth // session with user and token

In my expectation I should just need to send my auth header like this:
Delete /logout/

Authorization:username "myUser" token "§#token$%"

And hapi or frame would write this to request.auth, but this is not the case, so frames auth informations are not not coming from the http authorisation header.. I guess?

More informations would be great and helpful.

Fix for logout handler

var credentials = request.auth.credentials || { user: {} };

We need to add an extra check after we get credentials, incase the user property is null.

var credentials = request.auth.credentials || { user: {} };
var user = credentials.user || {}; // this is the fix

start failed with following errors

events.js:72
throw er; // Unhandled 'error' event
^
Error: listen EADDRINUSE
at errnoException (net.js:901:11)
at Server._listen2 (net.js:1039:14)
at listen (net.js:1061:10)
at net.js:1135:9
at dns.js:72:18
at process._tickDomainCallback (node.js:459:13)

config.js best practice

Hi,

I was just wandering what would be best practice with regards to git committing the config.js obviously it holds some sensitive data but not quite sure how this would fit into using a CI tool with automated deploys.

CORS

How should we deal with CORS?

Since we register two server, one for gui components and another for the api, we have to deal with http header manipulation at some point.

I will read more about this topic now, but from what I can tell now we have to add some flags to hapi.

CORS Cross-Origin Resource Sharing

Multiple logins/sessions

I've noticed that when you log in multiple times, the previous logins are removed and hence invalidated. This means that you can't log in from different locations. Is this intentional or just something left for the implementor to add?

It seems the invalidation happens in Session.create, where you clear out other sessions from the same user apart from the one just created.

It seems to make sense for when there is only 1 client for the api, but if there multiple clients, each login will invalidate the login of other clients. Just wondering what the rationale was for this?

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.