├── public
├── splash.png
├── pyramid.png
├── logo.svg
├── title.svg
└── style.css
├── app
├── Models
│ ├── Token.js
│ ├── PasswordReset.js
│ ├── Hooks
│ │ └── User.js
│ └── User.js
├── Controllers
│ └── Http
│ │ └── Auth
│ │ ├── AuthenticatedController.js
│ │ ├── LoginController.js
│ │ ├── RegisterController.js
│ │ └── PasswordResetController.js
└── Middleware
│ └── Authenticated.js
├── resources
└── views
│ ├── home.edge
│ ├── auth
│ ├── emails
│ │ ├── password_reset.edge
│ │ └── confirm_email.edge
│ ├── passwords
│ │ ├── email.edge
│ │ └── reset.edge
│ ├── login.edge
│ └── register.edge
│ ├── includes
│ └── notification.edge
│ └── layout
│ └── app.edge
├── .editorconfig
├── .gitignore
├── .env.example
├── database
├── migrations
│ ├── 1517537180329_password_reset_schema.js
│ ├── 1503248427886_token.js
│ └── 1503248427885_user.js
└── factory.js
├── start
├── hooks.js
├── routes.js
├── kernel.js
└── app.js
├── README.md
├── ace
├── server.js
├── package.json
└── config
├── auth.js
├── database.js
├── mail.js
├── cors.js
├── session.js
├── bodyParser.js
├── shield.js
└── app.js
/public/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ammezie/complete-adonis-auth/HEAD/public/splash.png
--------------------------------------------------------------------------------
/public/pyramid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ammezie/complete-adonis-auth/HEAD/public/pyramid.png
--------------------------------------------------------------------------------
/app/Models/Token.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Model = use('Model')
4 |
5 | class Token extends Model {
6 | }
7 |
8 | module.exports = Token
9 |
--------------------------------------------------------------------------------
/app/Models/PasswordReset.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Model = use('Model')
4 |
5 | class PasswordReset extends Model {
6 | }
7 |
8 | module.exports = PasswordReset
9 |
--------------------------------------------------------------------------------
/resources/views/home.edge:
--------------------------------------------------------------------------------
1 | @layout('layout.app')
2 |
3 | @section('content')
4 |
5 | Welcome {{ auth.user.username }}!
6 |
7 | @endsection
--------------------------------------------------------------------------------
/resources/views/auth/emails/password_reset.edge:
--------------------------------------------------------------------------------
1 |
2 | Use the link below to reset your password:
3 |
4 |
5 | Reset password
--------------------------------------------------------------------------------
/resources/views/includes/notification.edge:
--------------------------------------------------------------------------------
1 | @if(flashMessage('notification'))
2 |
3 | {{ flashMessage('notification.message') }}
4 |
5 | @endif
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_size = 2
6 | indent_style = space
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/resources/views/auth/emails/confirm_email.edge:
--------------------------------------------------------------------------------
1 | Hi {{ username }},
2 |
3 |
4 | Welcome to Adonisjs, please confirm your email address by clicking the link below:
5 |
6 |
7 |
8 | Confirm email address
9 |
--------------------------------------------------------------------------------
/app/Controllers/Http/Auth/AuthenticatedController.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | class AuthenticatedController {
4 | async logout ({ auth, response }) {
5 | await auth.logout()
6 |
7 | return response.redirect('/login')
8 | }
9 | }
10 |
11 | module.exports = AuthenticatedController
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Node modules
2 | node_modules
3 |
4 | # Adonis directory for storing tmp files
5 | tmp
6 |
7 | # Environment variables, never commit this file
8 | .env
9 |
10 | # Lock files
11 | package-lock.json
12 | yarn.lock
13 |
14 | # The development sqlite file
15 | database/development.sqlite
16 |
--------------------------------------------------------------------------------
/app/Middleware/Authenticated.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | class Authenticated {
4 | async handle ({ request, auth, response }, next) {
5 | try {
6 | await auth.check()
7 |
8 | return response.route('home')
9 | } catch (error) {
10 | await next()
11 | }
12 | }
13 | }
14 |
15 | module.exports = Authenticated
16 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | HOST=127.0.0.1
2 | PORT=3333
3 | NODE_ENV=development
4 | APP_URL=http://${HOST}:${PORT}
5 |
6 | CACHE_VIEWS=false
7 |
8 | APP_KEY=2wsjLSopTjD6WQEztTYIZgCFou8wpLJn
9 |
10 | DB_CONNECTION=sqlite
11 | DB_HOST=127.0.0.1
12 | DB_PORT=3306
13 | DB_USER=root
14 | DB_PASSWORD=
15 | DB_DATABASE=adonis
16 |
17 | SESSION_DRIVER=cookie
18 |
--------------------------------------------------------------------------------
/public/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/Models/Hooks/User.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Hash = use('Hash')
4 |
5 | const UserHook = module.exports = {}
6 |
7 | /**
8 | * Hash using password as a hook.
9 | *
10 | * @method
11 | *
12 | * @param {Object} userInstance
13 | *
14 | * @return {void}
15 | */
16 | UserHook.hashPassword = async (userInstance) => {
17 | if (userInstance.password) {
18 | userInstance.password = await Hash.make(userInstance.password)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/database/migrations/1517537180329_password_reset_schema.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Schema = use('Schema')
4 |
5 | class PasswordResetSchema extends Schema {
6 | up () {
7 | this.create('password_resets', table => {
8 | table.increments()
9 | table.string('email')
10 | table.string('token')
11 | table.timestamps()
12 | })
13 | }
14 |
15 | down () {
16 | this.drop('password_resets')
17 | }
18 | }
19 |
20 | module.exports = PasswordResetSchema
21 |
--------------------------------------------------------------------------------
/start/hooks.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { hooks } = require('@adonisjs/ignitor')
4 |
5 | hooks.after.providersBooted(() => {
6 | const View = use('View')
7 | const Env = use('Env')
8 | const Exception = use('Exception')
9 |
10 | View.global('appUrl', path => {
11 | const APP_URL = Env.get('APP_URL')
12 |
13 | return path ? `${APP_URL}/${path}` : APP_URL
14 | })
15 |
16 | // handle `InvalidSessionException`
17 | Exception.handle('InvalidSessionException', (error, { response }) => {
18 | return response.redirect('/login')
19 | })
20 | })
21 |
--------------------------------------------------------------------------------
/database/factory.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /*
4 | |--------------------------------------------------------------------------
5 | | Factory
6 | |--------------------------------------------------------------------------
7 | |
8 | | Factories are used to define blueprints for database tables or Lucid
9 | | models. Later you can use these blueprints to seed your database
10 | | with dummy data.
11 | |
12 | */
13 |
14 | // const Factory = use('Factory')
15 |
16 | /**
17 | Factory.blueprint('App/Models/User', (faker) => {
18 | return {
19 | username: faker.username()
20 | }
21 | })
22 | */
23 |
--------------------------------------------------------------------------------
/database/migrations/1503248427886_token.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Schema = use('Schema')
4 |
5 | class TokensSchema extends Schema {
6 | up () {
7 | this.create('tokens', table => {
8 | table.increments()
9 | table.integer('user_id').unsigned().references('id').inTable('users')
10 | table.string('token', 40).notNullable().unique()
11 | table.string('type', 80).notNullable()
12 | table.boolean('is_revoked').defaultTo(false)
13 | table.timestamps()
14 | })
15 | }
16 |
17 | down () {
18 | this.drop('tokens')
19 | }
20 | }
21 |
22 | module.exports = TokensSchema
23 |
--------------------------------------------------------------------------------
/database/migrations/1503248427885_user.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Schema = use('Schema')
4 |
5 | class UserSchema extends Schema {
6 | up () {
7 | this.create('users', table => {
8 | table.increments()
9 | table.string('username', 80).notNullable().unique()
10 | table.string('email', 254).notNullable().unique()
11 | table.string('password', 60).notNullable()
12 | table.string('confirmation_token')
13 | table.boolean('is_active').defaultTo(0)
14 | table.timestamps()
15 | })
16 | }
17 |
18 | down () {
19 | this.drop('users')
20 | }
21 | }
22 |
23 | module.exports = UserSchema
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Adonis fullstack application
2 |
3 | This is the fullstack boilerplate for AdonisJs, it comes pre-configured with.
4 |
5 | 1. Bodyparser
6 | 2. Session
7 | 3. Authentication
8 | 4. Web security middleware
9 | 5. CORS
10 | 6. Edge template engine
11 | 7. Lucid ORM
12 | 8. Migrations and seeds
13 |
14 | ## Setup
15 |
16 | Use the adonis command to install the blueprint
17 |
18 | ```bash
19 | adonis new yardstick
20 | ```
21 |
22 | or manually clone the repo and then run `npm install`.
23 |
24 |
25 | ### Migrations
26 |
27 | Run the following command to run startup migrations.
28 |
29 | ```js
30 | adonis migration:run
31 | ```
32 |
--------------------------------------------------------------------------------
/ace:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /*
4 | |--------------------------------------------------------------------------
5 | | Ace Commands
6 | |--------------------------------------------------------------------------
7 | |
8 | | The ace file is just a regular Javascript file but with no extension. You
9 | | can call `node ace` followed by the command name and it just works.
10 | |
11 | | Also you can use `adonis` followed by the command name, since the adonis
12 | | global proxy all the ace commands.
13 | |
14 | */
15 |
16 | const { Ignitor } = require('@adonisjs/ignitor')
17 |
18 | new Ignitor(require('@adonisjs/fold'))
19 | .appRoot(__dirname)
20 | .fireAce()
21 | .catch(console.error)
22 |
--------------------------------------------------------------------------------
/app/Models/User.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Model = use('Model')
4 |
5 | class User extends Model {
6 | static boot () {
7 | super.boot()
8 |
9 | /**
10 | * A hook to bash the user password before saving
11 | * it to the database.
12 | *
13 | * Look at `app/Models/Hooks/User.js` file to
14 | * check the hashPassword method
15 | */
16 | this.addHook('beforeCreate', 'User.hashPassword')
17 | }
18 |
19 | /**
20 | * A relationship on tokens is required for auth to
21 | * work. Since features like `refreshTokens` or
22 | * `rememberToken` will be saved inside the
23 | * tokens table.
24 | *
25 | * @method tokens
26 | *
27 | * @return {Object}
28 | */
29 | tokens () {
30 | return this.hasMany('App/Models/Token')
31 | }
32 | }
33 |
34 | module.exports = User
35 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /*
4 | |--------------------------------------------------------------------------
5 | | Http server
6 | |--------------------------------------------------------------------------
7 | |
8 | | This file bootstrap Adonisjs to start the HTTP server. You are free to
9 | | customize the process of booting the http server.
10 | |
11 | | """ Loading ace commands """
12 | | At times you may want to load ace commands when starting the HTTP server.
13 | | Same can be done by chaining `loadCommands()` method after
14 | |
15 | | """ Preloading files """
16 | | Also you can preload files by calling `preLoad('path/to/file')` method.
17 | | Make sure to pass relative path from the project root.
18 | */
19 |
20 | const { Ignitor } = require('@adonisjs/ignitor')
21 |
22 | new Ignitor(require('@adonisjs/fold'))
23 | .appRoot(__dirname)
24 | .fireHttpServer()
25 | .catch(console.error)
26 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "adonis-fullstack-app",
3 | "version": "4.0.0",
4 | "adonis-version": "4.0.0",
5 | "description": "The fullstack application boilerplate for Adonisjs",
6 | "main": "index.js",
7 | "scripts": {
8 | "start": "node server.js",
9 | "test": "node ace test"
10 | },
11 | "keywords": [
12 | "adonisjs",
13 | "adonis-app"
14 | ],
15 | "author": "",
16 | "license": "UNLICENSED",
17 | "private": true,
18 | "dependencies": {
19 | "@adonisjs/ace": "^4.0.7",
20 | "@adonisjs/auth": "^2.0.10",
21 | "@adonisjs/bodyparser": "^2.0.0",
22 | "@adonisjs/cors": "^1.0.3",
23 | "@adonisjs/fold": "^4.0.5",
24 | "@adonisjs/framework": "^4.0.28",
25 | "@adonisjs/ignitor": "^1.0.14",
26 | "@adonisjs/lucid": "^4.0.24",
27 | "@adonisjs/mail": "^3.0.4",
28 | "@adonisjs/session": "^1.0.19",
29 | "@adonisjs/shield": "^1.0.4",
30 | "@adonisjs/validator": "^5.0.0",
31 | "mysql": "^2.15.0",
32 | "random-string": "^0.2.0"
33 | },
34 | "devDependencies": {},
35 | "autoload": {
36 | "App": "./app"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/resources/views/auth/passwords/email.edge:
--------------------------------------------------------------------------------
1 | @layout('layout.app')
2 |
3 | @section('content')
4 |
5 |
6 |
Reset Password
7 |
8 | @include('includes.notification')
9 |
10 |
31 |
32 |
33 | @endsection
--------------------------------------------------------------------------------
/app/Controllers/Http/Auth/LoginController.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const User = use('App/Models/User')
4 | const Hash = use('Hash')
5 |
6 | class LoginController {
7 | showLoginForm ({ view }) {
8 | return view.render('auth.login')
9 | }
10 |
11 | async login ({ request, auth, session, response }) {
12 | // get form data
13 | const { email, password, remember } = request.all()
14 |
15 | // retrieve user base on the form data
16 | const user = await User.query()
17 | .where('email', email)
18 | .where('is_active', true)
19 | .first()
20 |
21 | if (user) {
22 | // verify password
23 | const passwordVerified = await Hash.verify(password, user.password)
24 |
25 | if (passwordVerified) {
26 | // login user
27 | await auth.remember(!!remember).login(user)
28 |
29 | return response.route('home')
30 | }
31 | }
32 |
33 | // display error message
34 | session.flash({
35 | notification: {
36 | type: 'danger',
37 | message: `We couldn't verify your credentials. Make sure you've confirmed your email address.`
38 | }
39 | })
40 |
41 | return response.redirect('back')
42 | }
43 | }
44 |
45 | module.exports = LoginController
46 |
--------------------------------------------------------------------------------
/start/routes.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /*
4 | |--------------------------------------------------------------------------
5 | | Routes
6 | |--------------------------------------------------------------------------
7 | |
8 | | Http routes are entry points to your web application. You can create
9 | | routes for different URL's and bind Controller actions to them.
10 | |
11 | | A complete guide on routing is available here.
12 | | http://adonisjs.com/docs/4.0/routing
13 | |
14 | */
15 |
16 | const Route = use('Route')
17 |
18 | Route.on('/').render('home').as('home').middleware(['auth'])
19 |
20 | Route.get('register', 'Auth/RegisterController.showRegisterForm').middleware([
21 | 'authenticated'
22 | ])
23 | Route.post('register', 'Auth/RegisterController.register').as('register')
24 | Route.get('register/confirm/:token', 'Auth/RegisterController.confirmEmail')
25 | Route.get('login', 'Auth/LoginController.showLoginForm').middleware([
26 | 'authenticated'
27 | ])
28 | Route.post('login', 'Auth/LoginController.login').as('login')
29 | Route.get('logout', 'Auth/AuthenticatedController.logout')
30 | Route.get('password/reset', 'Auth/PasswordResetController.showLinkRequestForm')
31 | Route.post('password/email', 'Auth/PasswordResetController.sendResetLinkEmail')
32 | Route.get('password/reset/:token', 'Auth/PasswordResetController.showResetForm')
33 | Route.post('password/reset', 'Auth/PasswordResetController.reset')
34 |
--------------------------------------------------------------------------------
/resources/views/auth/login.edge:
--------------------------------------------------------------------------------
1 | @layout('layout.app')
2 |
3 | @section('content')
4 |
5 |
6 |
Login
7 |
8 | @include('includes.notification')
9 |
10 |
46 |
47 |
48 | Forgot password?
49 |
50 |
51 |
52 | @endsection
--------------------------------------------------------------------------------
/resources/views/layout/app.edge:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Complete Authentication In AdonisJs
8 |
9 |
10 |
11 |
12 |
43 |
44 |
45 |
46 | @!section('content')
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/public/title.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/start/kernel.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Server = use('Server')
4 |
5 | /*
6 | |--------------------------------------------------------------------------
7 | | Global Middleware
8 | |--------------------------------------------------------------------------
9 | |
10 | | Global middleware are executed on each http request only when the routes
11 | | match.
12 | |
13 | */
14 | const globalMiddleware = [
15 | 'Adonis/Middleware/BodyParser',
16 | 'Adonis/Middleware/Session',
17 | 'Adonis/Middleware/Shield',
18 | 'Adonis/Middleware/AuthInit'
19 | ]
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | Named Middleware
24 | |--------------------------------------------------------------------------
25 | |
26 | | Named middleware is key/value object to conditionally add middleware on
27 | | specific routes or group of routes.
28 | |
29 | | // define
30 | | {
31 | | auth: 'Adonis/Middleware/Auth'
32 | | }
33 | |
34 | | // use
35 | | Route.get().middleware('auth')
36 | |
37 | */
38 | const namedMiddleware = {
39 | auth: 'Adonis/Middleware/Auth',
40 | authenticated: 'App/Middleware/Authenticated'
41 | }
42 |
43 | /*
44 | |--------------------------------------------------------------------------
45 | | Server Middleware
46 | |--------------------------------------------------------------------------
47 | |
48 | | Server levl middleware are executed even when route for a given URL is
49 | | not registered. Features like `static assets` and `cors` needs better
50 | | control over request lifecycle.
51 | |
52 | */
53 | const serverMiddleware = ['Adonis/Middleware/Static', 'Adonis/Middleware/Cors']
54 |
55 | Server.registerGlobal(globalMiddleware)
56 | .registerNamed(namedMiddleware)
57 | .use(serverMiddleware)
58 |
--------------------------------------------------------------------------------
/public/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Montserrat:300');
2 |
3 | html, body {
4 | height: 100%;
5 | width: 100%;
6 | }
7 |
8 | body {
9 | font-family: 'Montserrat', sans-serif;
10 | font-weight: 300;
11 | background-image: url("/splash.png");
12 | background-color: #220052;
13 | }
14 |
15 | * {
16 | margin: 0;
17 | padding: 0;
18 | }
19 |
20 | section {
21 | height: 100%;
22 | display: flex;
23 | flex-direction: column;
24 | justify-content: center;
25 | align-items: center;
26 | max-width: 536px;
27 | margin: auto;
28 | position: relative;
29 | }
30 |
31 | section:before {
32 | content: "";
33 | position: absolute;
34 | background: url("/pyramid.png") no-repeat;
35 | background-size: 100%;
36 | width: 100%;
37 | height: 402px;
38 | z-index: -1;
39 | }
40 |
41 | .logo {
42 | background: url("/logo.svg") no-repeat;
43 | width: 36px;
44 | height: 33px;
45 | background-size: 100%;
46 | margin-bottom: 35px;
47 | opacity: 0;
48 | animation: slideUp 1s cubic-bezier(0.19, 1, 0.30, 1) 1.3s forwards;
49 | }
50 |
51 | .title {
52 | background: url("/title.svg") no-repeat;
53 | width: 219px;
54 | height: 36px;
55 | background-size: 100%;
56 | opacity: 0;
57 | animation: slideUp 1s cubic-bezier(0.19, 1, 0.30, 1) 0.2s forwards;
58 | }
59 |
60 | .subtitle {
61 | margin-top: 25px;
62 | color: #BDB3CB;
63 | font-size: 17px;
64 | text-align: center;
65 | letter-spacing: 0.5;
66 | opacity: 0;
67 | animation: slideUp 1s cubic-bezier(0.19, 1, 0.30, 1) 0.5s forwards;
68 | }
69 |
70 | @keyframes slideUp {
71 | 0% {
72 | transform: translateY(40px);
73 | opacity: 0;
74 | }
75 | 50% {
76 | opacity: 0.2%;
77 | }
78 | 100% {
79 | opacity: 1;
80 | transform: none;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/start/app.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /*
4 | |--------------------------------------------------------------------------
5 | | Providers
6 | |--------------------------------------------------------------------------
7 | |
8 | | Providers are building blocks for your Adonis app. Anytime you install
9 | | a new Adonis specific package, chances are you will register the
10 | | provider here.
11 | |
12 | */
13 | const providers = [
14 | '@adonisjs/framework/providers/AppProvider',
15 | '@adonisjs/framework/providers/ViewProvider',
16 | '@adonisjs/lucid/providers/LucidProvider',
17 | '@adonisjs/bodyparser/providers/BodyParserProvider',
18 | '@adonisjs/cors/providers/CorsProvider',
19 | '@adonisjs/shield/providers/ShieldProvider',
20 | '@adonisjs/session/providers/SessionProvider',
21 | '@adonisjs/auth/providers/AuthProvider',
22 | '@adonisjs/mail/providers/MailProvider',
23 | '@adonisjs/validator/providers/ValidatorProvider'
24 | ]
25 |
26 | /*
27 | |--------------------------------------------------------------------------
28 | | Ace Providers
29 | |--------------------------------------------------------------------------
30 | |
31 | | Ace providers are required only when running ace commands. For example
32 | | Providers for migrations, tests etc.
33 | |
34 | */
35 | const aceProviders = ['@adonisjs/lucid/providers/MigrationsProvider']
36 |
37 | /*
38 | |--------------------------------------------------------------------------
39 | | Aliases
40 | |--------------------------------------------------------------------------
41 | |
42 | | Aliases are short unique names for IoC container bindings. You are free
43 | | to create your own aliases.
44 | |
45 | | For example:
46 | | { Route: 'Adonis/Src/Route' }
47 | |
48 | */
49 | const aliases = {}
50 |
51 | /*
52 | |--------------------------------------------------------------------------
53 | | Commands
54 | |--------------------------------------------------------------------------
55 | |
56 | | Here you store ace commands for your package
57 | |
58 | */
59 | const commands = []
60 |
61 | module.exports = { providers, aceProviders, aliases, commands }
62 |
--------------------------------------------------------------------------------
/resources/views/auth/register.edge:
--------------------------------------------------------------------------------
1 | @layout('layout.app')
2 |
3 | @section('content')
4 |
5 |
6 |
Register
7 |
8 | @include('includes.notification')
9 |
10 |
59 |
60 |
61 | @endsection
--------------------------------------------------------------------------------
/config/auth.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = {
4 | /*
5 | |--------------------------------------------------------------------------
6 | | Authenticator
7 | |--------------------------------------------------------------------------
8 | |
9 | | Authentication is a combination of serializer and scheme with extra
10 | | config to define on how to authenticate a user.
11 | |
12 | | Available Schemes - basic, session, jwt, api
13 | | Available Serializers - lucid, database
14 | |
15 | */
16 | authenticator: 'session',
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Session
21 | |--------------------------------------------------------------------------
22 | |
23 | | Session authenticator makes use of sessions to authenticate a user.
24 | | Session authentication is always persistent.
25 | |
26 | */
27 | session: {
28 | serializer: 'lucid',
29 | model: 'App/Models/User',
30 | scheme: 'session',
31 | uid: 'email',
32 | password: 'password'
33 | },
34 |
35 | /*
36 | |--------------------------------------------------------------------------
37 | | Basic Auth
38 | |--------------------------------------------------------------------------
39 | |
40 | | The basic auth authenticator uses basic auth header to authenticate a
41 | | user.
42 | |
43 | | NOTE:
44 | | This scheme is not persistent and users are supposed to pass
45 | | login credentials on each request.
46 | |
47 | */
48 | basic: {
49 | serializer: 'lucid',
50 | model: 'App/Models/User',
51 | scheme: 'basic',
52 | uid: 'email',
53 | password: 'password'
54 | },
55 |
56 | /*
57 | |--------------------------------------------------------------------------
58 | | Jwt
59 | |--------------------------------------------------------------------------
60 | |
61 | | The jwt authenticator works by passing a jwt token on each HTTP request
62 | | via HTTP `Authorization` header.
63 | |
64 | */
65 | jwt: {
66 | serializer: 'lucid',
67 | model: 'App/Models/User',
68 | scheme: 'jwt',
69 | uid: 'email',
70 | password: 'password',
71 | options: {
72 | secret: 'self::app.appKey'
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/resources/views/auth/passwords/reset.edge:
--------------------------------------------------------------------------------
1 | @layout('layout.app')
2 |
3 | @section('content')
4 |
5 |
6 |
Reset Password
7 |
8 | @include('includes.notification')
9 |
10 |
61 |
62 |
63 | @endsection
64 |
--------------------------------------------------------------------------------
/config/database.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Env = use('Env')
4 | const Helpers = use('Helpers')
5 |
6 | module.exports = {
7 | /*
8 | |--------------------------------------------------------------------------
9 | | Default Connection
10 | |--------------------------------------------------------------------------
11 | |
12 | | Connection defines the default connection settings to be used while
13 | | interacting with SQL databases.
14 | |
15 | */
16 | connection: Env.get('DB_CONNECTION', 'sqlite'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Sqlite
21 | |--------------------------------------------------------------------------
22 | |
23 | | Sqlite is a flat file database and can be good choice under development
24 | | environment.
25 | |
26 | | npm i --save sqlite3
27 | |
28 | */
29 | sqlite: {
30 | client: 'sqlite3',
31 | connection: {
32 | filename: Helpers.databasePath(`${Env.get('DB_DATABASE', 'development')}.sqlite`)
33 | },
34 | useNullAsDefault: true
35 | },
36 |
37 | /*
38 | |--------------------------------------------------------------------------
39 | | MySQL
40 | |--------------------------------------------------------------------------
41 | |
42 | | Here we define connection settings for MySQL database.
43 | |
44 | | npm i --save mysql
45 | |
46 | */
47 | mysql: {
48 | client: 'mysql',
49 | connection: {
50 | host: Env.get('DB_HOST', 'localhost'),
51 | port: Env.get('DB_PORT', ''),
52 | user: Env.get('DB_USER', 'root'),
53 | password: Env.get('DB_PASSWORD', ''),
54 | database: Env.get('DB_DATABASE', 'adonis')
55 | }
56 | },
57 |
58 | /*
59 | |--------------------------------------------------------------------------
60 | | PostgreSQL
61 | |--------------------------------------------------------------------------
62 | |
63 | | Here we define connection settings for PostgreSQL database.
64 | |
65 | | npm i --save pg
66 | |
67 | */
68 | pg: {
69 | client: 'pg',
70 | connection: {
71 | host: Env.get('DB_HOST', 'localhost'),
72 | port: Env.get('DB_PORT', ''),
73 | user: Env.get('DB_USER', 'root'),
74 | password: Env.get('DB_PASSWORD', ''),
75 | database: Env.get('DB_DATABASE', 'adonis')
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/Controllers/Http/Auth/RegisterController.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { validateAll } = use('Validator')
4 | const User = use('App/Models/User')
5 | const randomString = require('random-string')
6 | const Mail = use('Mail')
7 |
8 | class RegisterController {
9 | showRegisterForm ({ view }) {
10 | return view.render('auth.register')
11 | }
12 |
13 | async register ({ request, session, response }) {
14 | // validate form inputs
15 | const validation = await validateAll(request.all(), {
16 | username: 'required|unique:users,username',
17 | email: 'required|email|unique:users,email',
18 | password: 'required'
19 | })
20 |
21 | if (validation.fails()) {
22 | session.withErrors(validation.messages()).flashExcept(['password'])
23 |
24 | return response.redirect('back')
25 | }
26 |
27 | // create user
28 | const user = await User.create({
29 | username: request.input('username'),
30 | email: request.input('email'),
31 | password: request.input('password'),
32 | confirmation_token: randomString({ length: 40 })
33 | })
34 |
35 | // send confirmation email
36 | await Mail.send('auth.emails.confirm_email', user.toJSON(), message => {
37 | message
38 | .to(user.email)
39 | .from('hello@adonisjs.com')
40 | .subject('Please confirm your email address')
41 | })
42 |
43 | // display success message
44 | session.flash({
45 | notification: {
46 | type: 'success',
47 | message: 'Registration successful! A mail has been sent to your email address, please confirm your email address.'
48 | }
49 | })
50 |
51 | return response.redirect('back')
52 | }
53 |
54 | async confirmEmail ({ params, session, response }) {
55 | // get user with the cinfirmation token
56 | const user = await User.findBy('confirmation_token', params.token)
57 |
58 | // set confirmation to null and is_active to true
59 | user.confirmation_token = null
60 | user.is_active = true
61 |
62 | // persist user to database
63 | await user.save()
64 |
65 | // display success message
66 | session.flash({
67 | notification: {
68 | type: 'success',
69 | message: 'Your email address has been confirmed.'
70 | }
71 | })
72 |
73 | return response.redirect('/login')
74 | }
75 | }
76 |
77 | module.exports = RegisterController
78 |
--------------------------------------------------------------------------------
/config/mail.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Env = use('Env')
4 |
5 | module.exports = {
6 | /*
7 | |--------------------------------------------------------------------------
8 | | Connection
9 | |--------------------------------------------------------------------------
10 | |
11 | | Connection to be used for sending emails. Each connection needs to
12 | | define a driver too.
13 | |
14 | */
15 | connection: Env.get('MAIL_CONNECTION', 'smtp'),
16 |
17 | /*
18 | |--------------------------------------------------------------------------
19 | | SMTP
20 | |--------------------------------------------------------------------------
21 | |
22 | | Here we define configuration for sending emails via SMTP.
23 | |
24 | */
25 | smtp: {
26 | driver: 'smtp',
27 | pool: true,
28 | port: 2525,
29 | host: Env.get('MAIL_HOST'),
30 | secure: false,
31 | auth: {
32 | user: Env.get('MAIL_USERNAME'),
33 | pass: Env.get('MAIL_PASSWORD')
34 | },
35 | maxConnections: 5,
36 | maxMessages: 100,
37 | rateLimit: 10
38 | },
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | SparkPost
43 | |--------------------------------------------------------------------------
44 | |
45 | | Here we define configuration for spark post. Extra options can be defined
46 | | inside the `extra` object.
47 | |
48 | | https://developer.sparkpost.com/api/transmissions.html#header-options-attributes
49 | |
50 | | extras: {
51 | | campaign_id: 'sparkpost campaign id',
52 | | options: { // sparkpost options }
53 | | }
54 | |
55 | */
56 | sparkpost: {
57 | driver: 'sparkpost',
58 | apiKey: Env.get('SPARKPOST_API_KEY'),
59 | extras: {}
60 | },
61 |
62 | /*
63 | |--------------------------------------------------------------------------
64 | | Mailgun
65 | |--------------------------------------------------------------------------
66 | |
67 | | Here we define configuration for mailgun. Extra options can be defined
68 | | inside the `extra` object.
69 | |
70 | | https://mailgun-documentation.readthedocs.io/en/latest/api-sending.html#sending
71 | |
72 | | extras: {
73 | | 'o:tag': '',
74 | | 'o:campaign': '',,
75 | | . . .
76 | | }
77 | |
78 | */
79 | mailgun: {
80 | driver: 'mailgun',
81 | domain: Env.get('MAILGUN_DOMAIN'),
82 | apiKey: Env.get('MAILGUN_API_KEY'),
83 | extras: {}
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/config/cors.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = {
4 | /*
5 | |--------------------------------------------------------------------------
6 | | Origin
7 | |--------------------------------------------------------------------------
8 | |
9 | | Set a list of origins to be allowed. The value can be one of the following
10 | |
11 | | Boolean: true - Allow current request origin
12 | | Boolean: false - Disallow all
13 | | String - Comma seperated list of allowed origins
14 | | Array - An array of allowed origins
15 | | String: * - A wildcard to allow current request origin
16 | | Function - Receives the current origin and should return one of the above values.
17 | |
18 | */
19 | origin: false,
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | Methods
24 | |--------------------------------------------------------------------------
25 | |
26 | | HTTP methods to be allowed. The value can be one of the following
27 | |
28 | | String - Comma seperated list of allowed methods
29 | | Array - An array of allowed methods
30 | |
31 | */
32 | methods: ['GET', 'PUT', 'POST'],
33 |
34 | /*
35 | |--------------------------------------------------------------------------
36 | | Headers
37 | |--------------------------------------------------------------------------
38 | |
39 | | List of headers to be allowed via Access-Control-Request-Headers header.
40 | | The value can be on of the following.
41 | |
42 | | Boolean: true - Allow current request headers
43 | | Boolean: false - Disallow all
44 | | String - Comma seperated list of allowed headers
45 | | Array - An array of allowed headers
46 | | String: * - A wildcard to allow current request headers
47 | | Function - Receives the current header and should return one of the above values.
48 | |
49 | */
50 | headers: true,
51 |
52 | /*
53 | |--------------------------------------------------------------------------
54 | | Expose Headers
55 | |--------------------------------------------------------------------------
56 | |
57 | | A list of headers to be exposed via `Access-Control-Expose-Headers`
58 | | header. The value can be on of the following.
59 | |
60 | | Boolean: false - Disallow all
61 | | String: Comma seperated list of allowed headers
62 | | Array - An array of allowed headers
63 | |
64 | */
65 | exposeHeaders: false,
66 |
67 | /*
68 | |--------------------------------------------------------------------------
69 | | Credentials
70 | |--------------------------------------------------------------------------
71 | |
72 | | Define Access-Control-Allow-Credentials header. It should always be a
73 | | boolean.
74 | |
75 | */
76 | credentials: false,
77 |
78 | /*
79 | |--------------------------------------------------------------------------
80 | | MaxAge
81 | |--------------------------------------------------------------------------
82 | |
83 | | Define Access-Control-Allow-Max-Age
84 | |
85 | */
86 | maxAge: 90
87 | }
88 |
--------------------------------------------------------------------------------
/config/session.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Env = use('Env')
4 |
5 | module.exports = {
6 | /*
7 | |--------------------------------------------------------------------------
8 | | Session Driver
9 | |--------------------------------------------------------------------------
10 | |
11 | | The session driver to be used for storing session values. It can be
12 | | cookie, file or redis.
13 | |
14 | | For `redis` driver, make sure to install and register `@adonisjs/redis`
15 | |
16 | */
17 | driver: Env.get('SESSION_DRIVER', 'cookie'),
18 |
19 | /*
20 | |--------------------------------------------------------------------------
21 | | Cookie Name
22 | |--------------------------------------------------------------------------
23 | |
24 | | The name of the cookie to be used for saving session id. Session ids
25 | | are signed and encrypted.
26 | |
27 | */
28 | cookieName: 'adonis-session',
29 |
30 | /*
31 | |--------------------------------------------------------------------------
32 | | Clear session when browser closes
33 | |--------------------------------------------------------------------------
34 | |
35 | | If this value is true, the session cookie will be temporary and will be
36 | | removed when browser closes.
37 | |
38 | */
39 | clearWithBrowser: true,
40 |
41 | /*
42 | |--------------------------------------------------------------------------
43 | | Session age
44 | |--------------------------------------------------------------------------
45 | |
46 | | This value is only used when `clearWithBrowser` is set to false. The
47 | | age must be a valid https://npmjs.org/package/ms string or should
48 | | be in milliseconds.
49 | |
50 | | Valid values are:
51 | | '2h', '10d', '5y', '2.5 hrs'
52 | |
53 | */
54 | age: '2h',
55 |
56 | /*
57 | |--------------------------------------------------------------------------
58 | | Cookie options
59 | |--------------------------------------------------------------------------
60 | |
61 | | Cookie options defines the options to be used for setting up session
62 | | cookie
63 | |
64 | */
65 | cookie: {
66 | httpOnly: true,
67 | sameSite: true,
68 | path: '/'
69 | },
70 |
71 | /*
72 | |--------------------------------------------------------------------------
73 | | Sessions location
74 | |--------------------------------------------------------------------------
75 | |
76 | | If driver is set to file, we need to define the relative location from
77 | | the temporary path or absolute url to any location.
78 | |
79 | */
80 | file: {
81 | location: 'sessions'
82 | },
83 |
84 | /*
85 | |--------------------------------------------------------------------------
86 | | Redis config
87 | |--------------------------------------------------------------------------
88 | |
89 | | The configuration for the redis driver. By default we reference it from
90 | | the redis file. But you are free to define an object here too.
91 | |
92 | */
93 | redis: 'self::redis.local'
94 | }
95 |
--------------------------------------------------------------------------------
/app/Controllers/Http/Auth/PasswordResetController.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { validate, validateAll } = use('Validator')
4 | const User = use('App/Models/User')
5 | const PasswordReset = use('App/Models/PasswordReset')
6 | const randomString = require('random-string')
7 | const Mail = use('Mail')
8 | const Hash = use('Hash')
9 |
10 | class PasswordResetController {
11 | showLinkRequestForm ({ view }) {
12 | return view.render('auth.passwords.email')
13 | }
14 |
15 | async sendResetLinkEmail ({ request, session, response }) {
16 | // validate form inputs
17 | const validation = await validate(request.only('email'), {
18 | email: 'required|email'
19 | })
20 |
21 | if (validation.fails()) {
22 | session.withErrors(validation.messages()).flashAll()
23 |
24 | return response.redirect('back')
25 | }
26 |
27 | try {
28 | // get user
29 | const user = await User.findBy('email', request.input('email'))
30 |
31 | await PasswordReset.query().where('email', user.email).delete()
32 |
33 | const { token } = await PasswordReset.create({
34 | email: user.email,
35 | token: randomString({ length: 40 })
36 | })
37 |
38 | const mailData = {
39 | user: user.toJSON(),
40 | token
41 | }
42 |
43 | await Mail.send('auth.emails.password_reset', mailData, message => {
44 | message
45 | .to(user.email)
46 | .from('hello@adonisjs.com')
47 | .subject('Password reset link')
48 | })
49 |
50 | session.flash({
51 | notification: {
52 | type: 'success',
53 | message: 'A password reset link has been sent to your email address.'
54 | }
55 | })
56 |
57 | return response.redirect('back')
58 | } catch (error) {
59 | session.flash({
60 | notification: {
61 | type: 'danger',
62 | message: 'Sorry, there is no user with this email address.'
63 | }
64 | })
65 |
66 | return response.redirect('back')
67 | }
68 | }
69 |
70 | showResetForm ({ params, view }) {
71 | return view.render('auth.passwords.reset', { token: params.token })
72 | }
73 |
74 | async reset ({ request, session, response }) {
75 | // validate form inputs
76 | const validation = await validateAll(request.all(), {
77 | token: 'required',
78 | email: 'required',
79 | password: 'required|confirmed'
80 | })
81 |
82 | if (validation.fails()) {
83 | session
84 | .withErrors(validation.messages())
85 | .flashExcept(['password', 'password_confirmation'])
86 |
87 | return response.redirect('back')
88 | }
89 |
90 | try {
91 | // get user by the provider email
92 | const user = await User.findBy('email', request.input('email'))
93 |
94 | // check if password reet token exist for user
95 | const token = await PasswordReset.query()
96 | .where('email', user.email)
97 | .where('token', request.input('token'))
98 | .first()
99 |
100 | if (!token) {
101 | // display error message
102 | session.flash({
103 | notification: {
104 | type: 'danger',
105 | message: 'This password reset token does not exist.'
106 | }
107 | })
108 |
109 | return response.redirect('back')
110 | }
111 |
112 | user.password = await Hash.make(request.input('password'))
113 | await user.save()
114 |
115 | // delete password reset token
116 | await PasswordReset.query().where('email', user.email).delete()
117 |
118 | // display success message
119 | session.flash({
120 | notification: {
121 | type: 'success',
122 | message: 'Your password has been reset!'
123 | }
124 | })
125 |
126 | return response.redirect('/login')
127 | } catch (error) {
128 | // display error message
129 | session.flash({
130 | notification: {
131 | type: 'danger',
132 | message: 'Sorry, there is no user with this email address.'
133 | }
134 | })
135 |
136 | return response.redirect('back')
137 | }
138 | }
139 | }
140 |
141 | module.exports = PasswordResetController
142 |
--------------------------------------------------------------------------------
/config/bodyParser.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = {
4 | /*
5 | |--------------------------------------------------------------------------
6 | | JSON Parser
7 | |--------------------------------------------------------------------------
8 | |
9 | | Below settings are applied when request body contains JSON payload. If
10 | | you want body parser to ignore JSON payload, then simply set `types`
11 | | to an empty array.
12 | */
13 | json: {
14 | /*
15 | |--------------------------------------------------------------------------
16 | | limit
17 | |--------------------------------------------------------------------------
18 | |
19 | | Defines the limit of JSON that can be sent by the client. If payload
20 | | is over 1mb it will not be processed.
21 | |
22 | */
23 | limit: '1mb',
24 |
25 | /*
26 | |--------------------------------------------------------------------------
27 | | strict
28 | |--------------------------------------------------------------------------
29 | |
30 | | When `scrict` is set to true, body parser will only parse Arrays and
31 | | Object. Otherwise everything parseable by `JSON.parse` is parsed.
32 | |
33 | */
34 | strict: true,
35 |
36 | /*
37 | |--------------------------------------------------------------------------
38 | | types
39 | |--------------------------------------------------------------------------
40 | |
41 | | Which content types are processed as JSON payloads. You are free to
42 | | add your own types here, but the request body should be parseable
43 | | by `JSON.parse` method.
44 | |
45 | */
46 | types: [
47 | 'application/json',
48 | 'application/json-patch+json',
49 | 'application/vnd.api+json',
50 | 'application/csp-report'
51 | ]
52 | },
53 |
54 | /*
55 | |--------------------------------------------------------------------------
56 | | Raw Parser
57 | |--------------------------------------------------------------------------
58 | |
59 | |
60 | |
61 | */
62 | raw: {
63 | types: [
64 | 'text/*'
65 | ]
66 | },
67 |
68 | /*
69 | |--------------------------------------------------------------------------
70 | | Form Parser
71 | |--------------------------------------------------------------------------
72 | |
73 | |
74 | |
75 | */
76 | form: {
77 | types: [
78 | 'application/x-www-form-urlencoded'
79 | ]
80 | },
81 |
82 | /*
83 | |--------------------------------------------------------------------------
84 | | Files Parser
85 | |--------------------------------------------------------------------------
86 | |
87 | |
88 | |
89 | */
90 | files: {
91 | types: [
92 | 'multipart/form-data'
93 | ],
94 |
95 | /*
96 | |--------------------------------------------------------------------------
97 | | Max Size
98 | |--------------------------------------------------------------------------
99 | |
100 | | Below value is the max size of all the files uploaded to the server. It
101 | | is validated even before files have been processed and hard exception
102 | | is thrown.
103 | |
104 | | Consider setting a reasonable value here, otherwise people may upload GB's
105 | | of files which will keep your server busy.
106 | |
107 | | Also this value is considered when `autoProcess` is set to true.
108 | |
109 | */
110 | maxSize: '20mb',
111 |
112 | /*
113 | |--------------------------------------------------------------------------
114 | | Auto Process
115 | |--------------------------------------------------------------------------
116 | |
117 | | Whether or not to auto-process files. Since HTTP servers handle files via
118 | | couple of specific endpoints. It is better to set this value off and
119 | | manually process the files when required.
120 | |
121 | | This value can contain a boolean or an array of route patterns
122 | | to be autoprocessed.
123 | */
124 | autoProcess: true,
125 |
126 | /*
127 | |--------------------------------------------------------------------------
128 | | Process Manually
129 | |--------------------------------------------------------------------------
130 | |
131 | | The list of routes that should not process files and instead rely on
132 | | manual process. This list should only contain routes when autoProcess
133 | | is to true. Otherwise everything is processed manually.
134 | |
135 | */
136 | processManually: []
137 |
138 | /*
139 | |--------------------------------------------------------------------------
140 | | Temporary file name
141 | |--------------------------------------------------------------------------
142 | |
143 | | Define a function, which should return a string to be used as the
144 | | tmp file name.
145 | |
146 | | If not defined, Bodyparser will use `uuid` as the tmp file name.
147 | |
148 | | To be defined as. If you are defining the function, then do make sure
149 | | to return a value from it.
150 | |
151 | | tmpFileName () {
152 | | return 'some-unique-value'
153 | | }
154 | |
155 | */
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/config/shield.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = {
4 | /*
5 | |--------------------------------------------------------------------------
6 | | Content Security Policy
7 | |--------------------------------------------------------------------------
8 | |
9 | | Content security policy filters out the origins not allowed to execute
10 | | and load resources like scripts, styles and fonts. There are wide
11 | | variety of options to choose from.
12 | */
13 | csp: {
14 | /*
15 | |--------------------------------------------------------------------------
16 | | Directives
17 | |--------------------------------------------------------------------------
18 | |
19 | | All directives are defined in camelCase and here is the list of
20 | | available directives and their possible values.
21 | |
22 | | https://content-security-policy.com
23 | |
24 | | @example
25 | | directives: {
26 | | defaultSrc: ['self', '@nonce', 'cdnjs.cloudflare.com']
27 | | }
28 | |
29 | */
30 | directives: {
31 | },
32 | /*
33 | |--------------------------------------------------------------------------
34 | | Report only
35 | |--------------------------------------------------------------------------
36 | |
37 | | Setting `reportOnly=true` will not block the scripts from running and
38 | | instead report them to a URL.
39 | |
40 | */
41 | reportOnly: false,
42 | /*
43 | |--------------------------------------------------------------------------
44 | | Set all headers
45 | |--------------------------------------------------------------------------
46 | |
47 | | Headers staring with `X` have been depreciated, since all major browsers
48 | | supports the standard CSP header. So its better to disable deperciated
49 | | headers, unless you want them to be set.
50 | |
51 | */
52 | setAllHeaders: false,
53 |
54 | /*
55 | |--------------------------------------------------------------------------
56 | | Disable on android
57 | |--------------------------------------------------------------------------
58 | |
59 | | Certain versions of android are buggy with CSP policy. So you can set
60 | | this value to true, to disable it for Android versions with buggy
61 | | behavior.
62 | |
63 | | Here is an issue reported on a different package, but helpful to read
64 | | if you want to know the behavior. https://github.com/helmetjs/helmet/pull/82
65 | |
66 | */
67 | disableAndroid: true
68 | },
69 |
70 | /*
71 | |--------------------------------------------------------------------------
72 | | X-XSS-Protection
73 | |--------------------------------------------------------------------------
74 | |
75 | | X-XSS Protection saves from applications from XSS attacks. It is adopted
76 | | by IE and later followed by some other browsers.
77 | |
78 | | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
79 | |
80 | */
81 | xss: {
82 | enabled: true,
83 | enableOnOldIE: false
84 | },
85 |
86 | /*
87 | |--------------------------------------------------------------------------
88 | | Iframe Options
89 | |--------------------------------------------------------------------------
90 | |
91 | | xframe defines whether or not your website can be embedded inside an
92 | | iframe. Choose from one of the following options.
93 | | @available options
94 | | DENY, SAMEORIGIN, ALLOW-FROM http://example.com
95 | |
96 | | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
97 | */
98 | xframe: 'DENY',
99 |
100 | /*
101 | |--------------------------------------------------------------------------
102 | | No Sniff
103 | |--------------------------------------------------------------------------
104 | |
105 | | Browsers have a habit of sniffing content-type of a response. Which means
106 | | files with .txt extension containing Javascript code will be executed as
107 | | Javascript. You can disable this behavior by setting nosniff to false.
108 | |
109 | | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
110 | |
111 | */
112 | nosniff: true,
113 |
114 | /*
115 | |--------------------------------------------------------------------------
116 | | No Open
117 | |--------------------------------------------------------------------------
118 | |
119 | | IE users can execute webpages in the context of your website, which is
120 | | a serious security risk. Below option will manage this for you.
121 | |
122 | */
123 | noopen: true,
124 |
125 | /*
126 | |--------------------------------------------------------------------------
127 | | CSRF Protection
128 | |--------------------------------------------------------------------------
129 | |
130 | | CSRF Protection adds another layer of security by making sure, actionable
131 | | routes does have a valid token to execute an action.
132 | |
133 | */
134 | csrf: {
135 | enable: true,
136 | methods: ['POST', 'PUT', 'DELETE'],
137 | filterUris: [],
138 | cookieOptions: {
139 | httpOnly: false,
140 | sameSite: true,
141 | path: '/',
142 | maxAge: 7200
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/config/app.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Env = use('Env')
4 |
5 | module.exports = {
6 | /*
7 | |--------------------------------------------------------------------------
8 | | App Key
9 | |--------------------------------------------------------------------------
10 | |
11 | | App key is a randomly generated 16 or 32 characters long string required
12 | | to encrypted cookies, sessions and other sensitive data.
13 | |
14 | */
15 | appKey: Env.get('APP_KEY'),
16 |
17 | http: {
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Allow Method Spoofing
21 | |--------------------------------------------------------------------------
22 | |
23 | | Method spoofing allows to make requests by spoofing the http verb.
24 | | Which means you can make a GET request but instruct the server to
25 | | treat as a POST or PUT request. If you want this feature, set the
26 | | below value to true.
27 | |
28 | */
29 | allowMethodSpoofing: true,
30 |
31 | /*
32 | |--------------------------------------------------------------------------
33 | | Trust Proxy
34 | |--------------------------------------------------------------------------
35 | |
36 | | Trust proxy defines whether X-Forwaded-* headers should be trusted or not.
37 | | When your application is behind a proxy server like nginx, these values
38 | | are set automatically and should be trusted. Apart from setting it
39 | | to true or false Adonis supports handful or ways to allow proxy
40 | | values. Read documentation for that.
41 | |
42 | */
43 | trustProxy: false,
44 |
45 | /*
46 | |--------------------------------------------------------------------------
47 | | Subdomains
48 | |--------------------------------------------------------------------------
49 | |
50 | | Offset to be used for returning subdomains for a given request.For
51 | | majority of applications it will be 2, until you have nested
52 | | sudomains.
53 | | cheatsheet.adonisjs.com - offset - 2
54 | | virk.cheatsheet.adonisjs.com - offset - 3
55 | |
56 | */
57 | subdomainOffset: 2,
58 |
59 | /*
60 | |--------------------------------------------------------------------------
61 | | JSONP Callback
62 | |--------------------------------------------------------------------------
63 | |
64 | | Default jsonp callback to be used when callback query string is missing
65 | | in request url.
66 | |
67 | */
68 | jsonpCallback: 'callback',
69 |
70 | /*
71 | |--------------------------------------------------------------------------
72 | | Etag
73 | |--------------------------------------------------------------------------
74 | |
75 | | Set etag on all HTTP response. In order to disable for selected routes,
76 | | you can call the `response.send` with an options object as follows.
77 | |
78 | | response.send('Hello', { ignoreEtag: true })
79 | |
80 | */
81 | etag: true
82 | },
83 |
84 | views: {
85 | /*
86 | |--------------------------------------------------------------------------
87 | | Cache Views
88 | |--------------------------------------------------------------------------
89 | |
90 | | Define whether or not to cache the compiled view. Set it to true in
91 | | production to optimize view loading time.
92 | |
93 | */
94 | cache: Env.get('CACHE_VIEWS', true)
95 | },
96 |
97 | static: {
98 | /*
99 | |--------------------------------------------------------------------------
100 | | Dot Files
101 | |--------------------------------------------------------------------------
102 | |
103 | | Define how to treat dot files when trying to server static resources.
104 | | By default it is set to ignore, which will pretend that dotfiles
105 | | does not exists.
106 | |
107 | | Can be one of the following
108 | | ignore, deny, allow
109 | |
110 | */
111 | dotfiles: 'ignore',
112 |
113 | /*
114 | |--------------------------------------------------------------------------
115 | | ETag
116 | |--------------------------------------------------------------------------
117 | |
118 | | Enable or disable etag generation
119 | |
120 | */
121 | etag: true,
122 |
123 | /*
124 | |--------------------------------------------------------------------------
125 | | Extensions
126 | |--------------------------------------------------------------------------
127 | |
128 | | Set file extension fallbacks. When set, if a file is not found, the given
129 | | extensions will be added to the file name and search for. The first
130 | | that exists will be served. Example: ['html', 'htm'].
131 | |
132 | */
133 | extensions: false
134 | },
135 |
136 | locales: {
137 | /*
138 | |--------------------------------------------------------------------------
139 | | Loader
140 | |--------------------------------------------------------------------------
141 | |
142 | | The loader to be used for fetching and updating locales. Below is the
143 | | list of available options.
144 | |
145 | | file, database
146 | |
147 | */
148 | loader: 'file',
149 |
150 | /*
151 | |--------------------------------------------------------------------------
152 | | Default Locale
153 | |--------------------------------------------------------------------------
154 | |
155 | | Default locale to be used by Antl provider. You can always switch drivers
156 | | in runtime or use the official Antl middleware to detect the driver
157 | | based on HTTP headers/query string.
158 | |
159 | */
160 | locale: 'en'
161 | },
162 |
163 | logger: {
164 | /*
165 | |--------------------------------------------------------------------------
166 | | Transport
167 | |--------------------------------------------------------------------------
168 | |
169 | | Transport to be used for logging messages. You can have multiple
170 | | transports using same driver.
171 | |
172 | | Available drivers are: `file` and `console`.
173 | |
174 | */
175 | transport: 'console',
176 |
177 | /*
178 | |--------------------------------------------------------------------------
179 | | Console Transport
180 | |--------------------------------------------------------------------------
181 | |
182 | | Using `console` driver for logging. This driver writes to `stdout`
183 | | and `stderr`
184 | |
185 | */
186 | console: {
187 | driver: 'console',
188 | name: 'adonis-app',
189 | level: 'info'
190 | },
191 |
192 | /*
193 | |--------------------------------------------------------------------------
194 | | File Transport
195 | |--------------------------------------------------------------------------
196 | |
197 | | File transport uses file driver and writes log messages for a given
198 | | file inside `tmp` directory for your app.
199 | |
200 | | For a different directory, set an absolute path for the filename.
201 | |
202 | */
203 | file: {
204 | driver: 'file',
205 | name: 'adonis-app',
206 | filename: 'adonis.log',
207 | level: 'info'
208 | }
209 | }
210 | }
211 |
--------------------------------------------------------------------------------