Skip to content

Commit

Permalink
feat: legacy login
Browse files Browse the repository at this point in the history
  • Loading branch information
NGPixel committed Jul 13, 2019
1 parent bd24ff2 commit 03e80bd
Show file tree
Hide file tree
Showing 12 changed files with 395 additions and 60 deletions.
116 changes: 115 additions & 1 deletion client/scss/legacy.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,120 @@ body {
min-height: 100vh;
}

// LOGIN

.login {
background-color: mc('grey', '900');
height: 100vh;
display: flex;
align-items: center;
justify-content: center;

&-deprecated {
position: absolute;
top: 0;
left: 0;
width: 100%;
background-color: mc('red', '700');
text-align: center;
color: mc('red', '50');
height: 64px;
display: flex;
align-items: center;
justify-content: center;

a {
color: #FFF;
margin-left: 5px;
}
}

&-dialog {
width: 650px;
background-color: mc('grey', '100');
border-radius: 5px;
text-align: center;
padding: 2rem;
color: mc('grey', '800');

h1 {
margin-bottom: 2rem;
}

input, select {
display: block;
background-color: #FFF;
border: none;
border-radius: 5px;
width: 100%;
height: 40px;
padding: 0 1rem;
margin: 5px 0;
}

button {
height: 40px;
display: block;
width: 200px;
border: none;
border-radius: 5px;
margin: 0 auto;
background-color: mc('blue', '700');
color: #FFF;
cursor: pointer;
margin-top: 1rem;
font-weight: 600;

&:hover {
background-color: mc('blue', '800');
}
}
}

&-social {
margin-top: 2rem;
padding-top: 1rem;
border-top: 1px solid mc('grey', '400');

h2 {
font-size: 14px;
font-weight: 600;
margin-bottom: 1rem;
}

&-icon {
display: inline-flex;
justify-content: center;
align-items: center;
border-radius: 5px;
width: 54px;
height: 54px;
cursor: pointer;
transition: opacity .2s ease;
margin: .5rem .25rem;
&:hover {
opacity: .8;
}
svg {
width: 24px;
height: 24px;
bottom: 0;
path {
fill: #FFF;
}
}

@each $colorName, $color in $material-colors {
&.#{$colorName} {
background-color: map-get($color, '500');
}
}
}
}
}

// PAGE

.header {
background-color: #000;
color: #FFF;
Expand Down Expand Up @@ -145,7 +259,7 @@ body {
}

&-right {
flex: 0 0 324px;
flex: 0 0 308px;
padding-left: 16px;

&-title {
Expand Down
53 changes: 2 additions & 51 deletions dev/templates/legacy.pug
Original file line number Diff line number Diff line change
Expand Up @@ -90,58 +90,9 @@ html

!= analyticsCode.head

if injectCode.css
style(type='text/css')!= injectCode.css
if injectCode.head
!= injectCode.head
block head

body
!= analyticsCode.bodyStart
#root
.header
span.header-title= siteConfig.title
span.header-deprecated Your browser is outdated. Upgrade to a #[a(href='https://bestvpn.org/outdatedbrowser/en', rel='nofollow') modern browser].
span.header-login
a(href='/login')
i.material-icons account_circle
.main
.sidebar
each navItem in sidebar
if navItem.kind === 'link'
a.sidebar-link(href=navItem.target)
i.material-icons= navItem.icon
span= navItem.label
else if navItem.kind === 'divider'
.sidebar-divider
else if navItem.kind === 'header'
.sidebar-title= navItem.label
.main-container
.page-header
.page-header-left
h1= page.title
h2= page.description
.page-header-right
.page-header-right-title Last edited by
.page-header-right-author= page.authorName
.page-header-right-updated= page.updatedAt
.page-contents
.contents
div!= page.render
if page.toc.length
.toc
.toc-title Table of Contents
each tocItem, tocIdx in page.toc
a.toc-tile(href='#' + tocItem.anchor)
i.material-icons arrow_right
span= tocItem.title
if tocIdx < page.toc.length - 1 || tocItem.children.length
.toc-divider
each tocSubItem in tocItem.children
a.toc-tile.inset(href='#' + tocSubItem.anchor)
i.material-icons arrow_right
span= tocSubItem.title
if tocIdx < page.toc.length - 1
.toc-divider.inset
if injectCode.body
!= injectCode.body
block body
!= analyticsCode.bodyEnd
2 changes: 1 addition & 1 deletion dev/webpack/webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ module.exports = {
}),
new HtmlWebpackPlugin({
template: 'dev/templates/legacy.pug',
filename: '../server/views/legacy.pug',
filename: '../server/views/legacy/master.pug',
hash: false,
inject: false,
excludeChunks: ['setup', 'app']
Expand Down
2 changes: 1 addition & 1 deletion dev/webpack/webpack.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ module.exports = {
}),
new HtmlWebpackPlugin({
template: 'dev/templates/legacy.pug',
filename: '../server/views/legacy.pug',
filename: '../server/views/legacy/master.pug',
hash: false,
inject: false,
excludeChunks: ['setup', 'app']
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"bcryptjs-then": "1.0.1",
"bluebird": "3.5.5",
"body-parser": "1.19.0",
"brute-knex": "4.0.0",
"chalk": "2.4.2",
"cheerio": "1.0.0-rc.3",
"chokidar": "3.0.1",
Expand Down
88 changes: 85 additions & 3 deletions server/controllers/auth.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,70 @@
/* global WIKI */

const express = require('express')
const ExpressBrute = require('express-brute')
const BruteKnex = require('brute-knex')
const router = express.Router()
const moment = require('moment')
const _ = require('lodash')
const fs = require('fs-extra')
const path = require('path')

const bruteforce = new ExpressBrute(new BruteKnex({
createTable: true,
knex: WIKI.models.knex
}), {
freeRetries: 5,
minWait: 5*60*1000, // 5 minutes
maxWait: 60*60*1000, // 1 hour
failCallback: (req, res, next) => {
res.status(401).send('Too many failed attempts. Try again later.')
}
})

/**
* Login form
*/
router.get('/login', (req, res, next) => {
router.get('/login', async (req, res, next) => {
_.set(res.locals, 'pageMeta.title', 'Login')
res.render('login')

if (req.query.legacy || req.get('user-agent').indexOf('Trident') >= 0) {
const strategies = await WIKI.models.authentication.query().select('key', 'selfRegistration').where({ isEnabled: true })
let formStrategies = []
let socialStrategies = []

// TODO: Let's refactor that at some point...
for (let stg of strategies) {
const stgInfo = _.find(WIKI.data.authentication, ['key', stg.key]) || {}
if (stgInfo.useForm) {
formStrategies.push({
key: stg.key,
title: stgInfo.title
})
} else {
socialStrategies.push({
...stgInfo,
...stg,
icon: await fs.readFile(path.join(WIKI.ROOTPATH, `assets/svg/auth-icon-${stg.key}.svg`), 'utf8').catch(err => {
if (err.code === 'ENOENT') {
return null
}
throw err
})
})
}
}
res.render('legacy/login', {
formStrategies,
socialStrategies
})
} else {
res.render('login')
}
})

/**
* Social Strategies Login
*/
router.get('/login/:strategy', async (req, res, next) => {
try {
await WIKI.models.users.login({
Expand All @@ -21,6 +74,10 @@ router.get('/login/:strategy', async (req, res, next) => {
next(err)
}
})

/**
* Social Strategies Callback
*/
router.all('/login/:strategy/callback', async (req, res, next) => {
if (req.method !== 'GET' && req.method !== 'POST') { return next() }

Expand All @@ -35,6 +92,30 @@ router.all('/login/:strategy/callback', async (req, res, next) => {
}
})

/**
* LEGACY - Login form handling
*/
router.post('/login', bruteforce.prevent, async (req, res, next) => {
_.set(res.locals, 'pageMeta.title', 'Login')

if (req.query.legacy || req.get('user-agent').indexOf('Trident') >= 0) {
try {
const authResult = await WIKI.models.users.login({
strategy: req.body.strategy,
username: req.body.user,
password: req.body.pass
}, { req, res })
req.brute.reset()
res.cookie('jwt', authResult.jwt, { expires: moment().add(1, 'y').toDate() })
res.redirect('/')
} catch (err) {
res.render('legacy/login')
}
} else {
res.redirect('/login')
}
})

/**
* Logout
*/
Expand All @@ -59,10 +140,11 @@ router.get('/register', async (req, res, next) => {
/**
* Verify
*/
router.get('/verify/:token', async (req, res, next) => {
router.get('/verify/:token', bruteforce.prevent, async (req, res, next) => {
const usr = await WIKI.models.userKeys.validateToken({ kind: 'verify', token: req.params.token })
await WIKI.models.users.query().patch({ isVerified: true }).where('id', usr.id)
const result = await WIKI.models.users.refreshToken(usr)
req.brute.reset()
res.cookie('jwt', result.token, { expires: moment().add(1, 'years').toDate() })
res.redirect('/')
})
Expand Down
2 changes: 1 addition & 1 deletion server/controllers/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ router.get('/*', async (req, res, next) => {
if (_.isString(page.toc)) {
page.toc = JSON.parse(page.toc)
}
res.render('legacy', { page, sidebar, injectCode })
res.render('legacy/page', { page, sidebar, injectCode })
} else {
res.render('page', { page, sidebar, injectCode })
}
Expand Down
21 changes: 21 additions & 0 deletions server/views/legacy/login.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
extends master.pug

block body
#root
.login-deprecated Your browser is outdated. Upgrade to a #[a(href='https://bestvpn.org/outdatedbrowser/en', rel='nofollow') modern browser].
.login
.login-dialog
form(method='post', action='/login')
h1= config.title
select(name='strategy')
each str in formStrategies
option(value=str.key, selected)= str.title
input(type='text', name='user', placeholder='Username / Email')
input(type='password', name='pass', placeholder='Password')
button(type='submit') Login
if socialStrategies.length
.login-social
h2 or login using...
each str in socialStrategies
a.login-social-icon(href='/login/' + str.key, class=str.color)
!= str.icon

0 comments on commit 03e80bd

Please sign in to comment.