├── 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 |
11 | {{ csrfField() }} 12 | 13 |
14 | 15 | 16 |
17 | 22 |
23 | 24 | {{ elIf('$self', getErrorFor('email'), hasErrorFor('email')) }} 25 |
26 | 27 |
28 | 29 |
30 |
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 |
11 | {{ csrfField() }} 12 | 13 |
14 | 15 | 16 |
17 | 21 |
22 |
23 | 24 |
25 | 26 | 27 |
28 | 32 |
33 |
34 | 35 |
36 | 40 |
41 | 42 |
43 | 44 |
45 |
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 |
11 | {{ csrfField() }} 12 | 13 |
14 | 15 | 16 |
17 | 22 |
23 | 24 | {{ elIf('$self', getErrorFor('username'), hasErrorFor('username')) }} 25 |
26 | 27 |
28 | 29 | 30 |
31 | 36 |
37 | 38 | {{ elIf('$self', getErrorFor('email'), hasErrorFor('email')) }} 39 |
40 | 41 |
42 | 43 | 44 |
45 | 50 |
51 | 52 | {{ elIf('$self', getErrorFor('password'), hasErrorFor('password')) }} 53 |
54 | 55 |
56 | 57 |
58 |
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 |
11 | {{ csrfField() }} 12 | 13 | 14 | 15 |
16 | 17 | 18 |
19 | 24 |
25 | 26 | {{ elIf('$self', getErrorFor('email'), hasErrorFor('email')) }} 27 |
28 | 29 |
30 | 31 | 32 |
33 | 38 |
39 | 40 | {{ elIf('$self', getErrorFor('password'), hasErrorFor('password')) }} 41 |
42 | 43 |
44 | 45 | 46 |
47 | 52 |
53 | 54 | {{ elIf('$self', getErrorFor('password_confirmation'), hasErrorFor('password_confirmation')) }} 55 |
56 | 57 |
58 | 59 |
60 |
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 | --------------------------------------------------------------------------------