<commit_before>'use strict'

if(process.env.NEW_RELIC_LICENSE_KEY) { require('newrelic') }

const _ = require('lodash')
const async = require('async')
const bparser = require('body-parser')
const cparser = require('cookie-parser')
const express = require('express')
const jwt = require('jsonwebtoken')
const mongo = require('mongodb')
const passport = require('passport')
const raven = require('raven')



// MONGODB
// ACCOUNTS
// JWT_SECRET

// GOOGLE_ID
// GOOGLE_SECRET

// FACEBOOK_ID
// FACEBOOK_SECRET

// TWITTER_KEY
// TWITTER_SECRET

// LIVE_ID
// LIVE_SECRET

// TAAT_ENTRYPOINT
// TAAT_ISSUER
// TAAT_CERT
// TAAT_PRIVATECERT



// passport (de)serialize
passport.serializeUser((user, done) => {
    done(null, user)
})

passport.deserializeUser((user, done) => {
    done(null, user)
})



// initialize getsentry.com client
if(process.env.SENTRY_DSN) {
    raven.config(process.env.SENTRY_DSN, {
        release: process.env.VERSION || process.env.HEROKU_SLUG_COMMIT.substr(0, 7) || require('./package').version,
        dataCallback: (data) => {
            _.unset(data, 'request.env')
            return data
        }
    }).install()
}



// start express app
const app = express()

// returns db connection (creates if not set)
app.locals.dbs = {}
app.locals.db = (account, callback) => {
    if(_.has(app, ['locals', 'dbs', account])) {
        return callback(null, app.locals.dbs[account].db(account))
    } else {
        var entuDb
        async.waterfall([
            (callback) => {
                mongo.MongoClient.connect(process.env.MONGODB, { ssl: true, sslValidate: true }, callback)
            },
            (connection, callback) => {
                entuDb = connection
                entuDb.collection('entity').findOne({ 'database_name.string': account, 'mongodb.string': { $exists: true } }, { _id: false, 'mongodb.string': true }, callback)
            },
            (url, callback) => {
                if (!_.has(url, 'mongodb.0.string')) { return callback('No MongoDb url')}

                mongo.MongoClient.connect(_.get(url, 'mongodb.0.string'), { ssl: true, sslValidate: true }, callback)
            },
            (connection, callback) => {
                console.log('Connected to ' + account)

                connection.on('close', () => {
                    _.unset(app, ['locals', 'dbs', account])
                    console.log('Disconnected from ' + account)
                })

                app.locals.dbs[account] = connection

                entuDb.close(callback)
            },
        ], (err) => {
            if(err) { return callback(err) }

            return callback(null, app.locals.dbs[account].db(account))
        })
    }
}

// Hide Powered By
app.disable('x-powered-by')

// get correct client IP behind nginx
app.set('trust proxy', true)

// logs to getsentry.com - start
if(process.env.SENTRY_DSN) { app.use(raven.requestHandler()) }

// Initialize Passport
app.use(passport.initialize())

// parse Cookies
app.use(cparser())

// parse POST/PUT requests body
app.use(bparser.json())

// save request info to request collection
app.use((req, res, next) => {
    req.startDt = Date.now()

    res.on('finish', () => {
        var request = {}

        _.set(request, 'date', new Date())
        _.set(request, 'ms', Date.now() - _.get(req, 'startDt'))
        _.set(request, 'status', res.statusCode)
        _.set(request, 'method', _.get(req, 'method'))
        _.set(request, 'path', _.get(req, 'originalUrl').split('?')[0])
        _.set(request, 'query', _.get(req, 'originalUrl').split('?')[1])
        _.set(request, 'body', _.get(req, 'body'))
        _.set(request, 'user.ip', _.get(req, 'ip'))
        _.set(request, 'user.account', _.get(req, 'account'))
        _.set(request, 'user.user', _.get(req, 'user'))
        _.set(request, 'user.browser', _.get(req, 'headers.user-agent'))

        if (_.isEmpty(request.body)) {
            _.unset(request, 'body')
        } else {
            request.body = JSON.stringify(request.body)
        }
        request.user = _.pickBy(request.user, _.identity)

        async.waterfall([
            (callback) => {
                req.app.locals.db(req.account || 'entu', callback)
            },
            (connection, callback) => {
                connection.collection('request').insertOne(_.pickBy(request, _.identity), callback)
            },
        ], (err) => {
            if(err) {
                console.error('Can\'t save request: ' + err.toString())
            }
        })
    })

    next(null)
})

// redirect HTTP to HTTPS
app.use((req, res, next) => {
    if (req.hostname !== 'localhost' && req.protocol.toLowerCase() !== 'https') { return next([418, 'I\'m a teapot']) } else { next() }
})

// check JWT
const jwtCheck = (req, res, next) => {
    let parts = _.get(req, 'headers.authorization', '').split(' ')
    let jwtConf = {
        issuer: req.hostname
    }

    if (req.query.account) {
        req.account = req.query.account
        jwtConf.audience = req.query.account
    }

    if(parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') { return next(null) }

    jwt.verify(parts[1], process.env.JWT_SECRET, jwtConf, (err, decoded) => {
        if(err) { return next([401, err]) }

        _.set(req, 'user', decoded.sub)
        _.set(req, 'account', decoded.aud)

        next(null)
    })
}

// routes mapping
app.use('/', require('./routes/index'))
app.use('/auth', require('./routes/auth/index'))
app.use('/auth/id-card', require('./routes/auth/id-card'))

app.use('/account', jwtCheck, require('./routes/account'))
app.use('/entity', jwtCheck, require('./routes/entity'))
app.use('/property', jwtCheck, require('./routes/property'))

// provider mapping (only if configured)
if(process.env.GOOGLE_ID && process.env.GOOGLE_SECRET) { app.use('/auth/google', require('./routes/auth/google')) }
if(process.env.FACEBOOK_ID && process.env.FACEBOOK_SECRET) { app.use('/auth/facebook', require('./routes/auth/facebook')) }
if(process.env.TWITTER_KEY && process.env.TWITTER_SECRET) { app.use('/auth/twitter', require('./routes/auth/twitter')) }
if(process.env.LIVE_ID && process.env.LIVE_SECRET) { app.use('/auth/live', require('./routes/auth/live')) }<commit_msg>Use IP and browser for JWT secret<commit_after>'use strict'

if(process.env.NEW_RELIC_LICENSE_KEY) { require('newrelic') }

const _ = require('lodash')
const async = require('async')
const bparser = require('body-parser')
const cparser = require('cookie-parser')
const express = require('express')
const jwt = require('jsonwebtoken')
const mongo = require('mongodb')
const passport = require('passport')
const raven = require('raven')



// MONGODB
// ACCOUNTS
// JWT_SECRET

// GOOGLE_ID
// GOOGLE_SECRET

// FACEBOOK_ID
// FACEBOOK_SECRET

// TWITTER_KEY
// TWITTER_SECRET

// LIVE_ID
// LIVE_SECRET

// TAAT_ENTRYPOINT
// TAAT_ISSUER
// TAAT_CERT
// TAAT_PRIVATECERT



// passport (de)serialize
passport.serializeUser((user, done) => {
    done(null, user)
})

passport.deserializeUser((user, done) => {
    done(null, user)
})



// initialize getsentry.com client
if(process.env.SENTRY_DSN) {
    raven.config(process.env.SENTRY_DSN, {
        release: process.env.VERSION || process.env.HEROKU_SLUG_COMMIT.substr(0, 7) || require('./package').version,
        dataCallback: (data) => {
            _.unset(data, 'request.env')
            return data
        }
    }).install()
}



// start express app
const app = express()

// returns db connection (creates if not set)
app.locals.dbs = {}
app.locals.db = (account, callback) => {
    if(_.has(app, ['locals', 'dbs', account])) {
        return callback(null, app.locals.dbs[account].db(account))
    } else {
        var entuDb
        async.waterfall([
            (callback) => {
                mongo.MongoClient.connect(process.env.MONGODB, { ssl: true, sslValidate: true }, callback)
            },
            (connection, callback) => {
                entuDb = connection
                entuDb.collection('entity').findOne({ 'database_name.string': account, 'mongodb.string': { $exists: true } }, { _id: false, 'mongodb.string': true }, callback)
            },
            (url, callback) => {
                if (!_.has(url, 'mongodb.0.string')) { return callback('No MongoDb url')}

                mongo.MongoClient.connect(_.get(url, 'mongodb.0.string'), { ssl: true, sslValidate: true }, callback)
            },
            (connection, callback) => {
                console.log('Connected to ' + account)

                connection.on('close', () => {
                    _.unset(app, ['locals', 'dbs', account])
                    console.log('Disconnected from ' + account)
                })

                app.locals.dbs[account] = connection

                entuDb.close(callback)
            },
        ], (err) => {
            if(err) { return callback(err) }

            return callback(null, app.locals.dbs[account].db(account))
        })
    }
}

// Hide Powered By
app.disable('x-powered-by')

// get correct client IP behind nginx
app.set('trust proxy', true)

// logs to getsentry.com - start
if(process.env.SENTRY_DSN) { app.use(raven.requestHandler()) }

// Initialize Passport
app.use(passport.initialize())

// parse Cookies
app.use(cparser())

// parse POST/PUT requests body
app.use(bparser.json())

// save request info to request collection
app.use((req, res, next) => {
    req.startDt = Date.now()

    res.on('finish', () => {
        var request = {}

        _.set(request, 'date', new Date())
        _.set(request, 'ms', Date.now() - _.get(req, 'startDt'))
        _.set(request, 'status', res.statusCode)
        _.set(request, 'method', _.get(req, 'method'))
        _.set(request, 'path', _.get(req, 'originalUrl').split('?')[0])
        _.set(request, 'query', _.get(req, 'originalUrl').split('?')[1])
        _.set(request, 'body', _.get(req, 'body'))
        _.set(request, 'user.ip', _.get(req, 'ip'))
        _.set(request, 'user.account', _.get(req, 'account'))
        _.set(request, 'user.user', _.get(req, 'user'))
        _.set(request, 'user.browser', _.get(req, 'headers.user-agent'))

        if (_.isEmpty(request.body)) {
            _.unset(request, 'body')
        } else {
            request.body = JSON.stringify(request.body)
        }
        request.user = _.pickBy(request.user, _.identity)

        async.waterfall([
            (callback) => {
                req.app.locals.db(req.account || 'entu', callback)
            },
            (connection, callback) => {
                connection.collection('request').insertOne(_.pickBy(request, _.identity), callback)
            },
        ], (err) => {
            if(err) {
                console.error('Can\'t save request: ' + err.toString())
            }
        })
    })

    next(null)
})

// redirect HTTP to HTTPS
app.use((req, res, next) => {
    if (req.hostname !== 'localhost' && req.protocol.toLowerCase() !== 'https') { return next([418, 'I\'m a teapot']) } else { next() }
})

// check JWT
const jwtCheck = (req, res, next) => {
    let parts = _.get(req, 'headers.authorization', '').split(' ')
    let jwtConf = {
        issuer: req.hostname
    }

    if (req.query.account) {
        req.account = req.query.account
        jwtConf.audience = req.query.account
    }

    if(parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') { return next(null) }

    jwt.verify(parts[1], process.env.JWT_SECRET + _.get(req, 'ip') + _.get(req, 'headers.user-agent'), jwtConf, (err, decoded) => {
        if(err) { return next([401, err]) }

        _.set(req, 'user', decoded.sub)
        _.set(req, 'account', decoded.aud)

        next(null)
    })
}

// routes mapping
app.use('/', require('./routes/index'))
app.use('/auth', require('./routes/auth/index'))
app.use('/auth/id-card', require('./routes/auth/id-card'))

app.use('/account', jwtCheck, require('./routes/account'))
app.use('/entity', jwtCheck, require('./routes/entity'))
app.use('/property', jwtCheck, require('./routes/property'))

// provider mapping (only if configured)
if(process.env.GOOGLE_ID && process.env.GOOGLE_SECRET) { app.use('/auth/google', require('./routes/auth/google')) }
if(process.env.FACEBOOK_ID && process.env.FACEBOOK_SECRET) { app.use('/auth/facebook', require('./routes/auth/facebook')) }
if(process.env.TWITTER_KEY && process.env.TWITTER_SECRET) { app.use('/auth/twitter', require('./routes/auth/twitter')) }
if(process.env.LIVE_ID && process.env.LIVE_SECRET) { app.use('/auth/live', require('./routes/auth/live')) }
{'fraction_non_alphanumeric': 0.18054449928355357, 'fraction_numerical': 0.002388154752427957, 'mean_word_length': 2.580222285551439, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4758482', 'n_tokens_mistral': 4185, 'n_tokens_neox': 4070, 'n_words': 764}