19 Commits
ci-07 ... ci-20

Author SHA1 Message Date
251aa6cf97 Remove source map annotations from minified libraries
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-28 19:29:00 -05:00
60003d64d5 Add front-end error logging
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-28 19:13:13 -05:00
535dde13ff Guarantee additional logging data object in permission middleware
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-19 10:19:01 -05:00
63d102296f Fix bad logging method call names
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-19 09:55:26 -05:00
77d203b2b0 Add missing service injection...
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-19 09:53:27 -05:00
fcbf25e3ce Check IAM policy for OAuth2 logins
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-19 09:51:36 -05:00
084ec7bbc1 inflate OpenID UID to case-sensitive on lookup
All checks were successful
continuous-integration/drone/push Build is passing
2020-10-19 09:39:28 -05:00
6b3339a883 Force OpenID UID to be lowercase
All checks were successful
continuous-integration/drone/push Build is passing
2020-10-19 09:35:49 -05:00
8f1bbfef56 OpenID - revert case insensitive session UID lookup
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-19 09:26:52 -05:00
e400e16ccc OpenID - revert case insensitive cast to UID
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-19 09:22:09 -05:00
97096f619f Make UID case-insensitive
All checks were successful
continuous-integration/drone/push Build is passing
2020-10-18 23:27:23 -05:00
2d97b77bbf Fix user bind error constructor
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-18 23:04:01 -05:00
5916222f7b Update libflitte
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-18 22:11:23 -05:00
bb79d52911 Increase error stack trace limit
All checks were successful
continuous-integration/drone/push Build is passing
2020-10-18 22:07:12 -05:00
2e05ec77c8 Increase error stack trace limit
All checks were successful
continuous-integration/drone/push Build is passing
2020-10-18 22:06:08 -05:00
433af8261f Add debug output
All checks were successful
continuous-integration/drone/push Build is passing
2020-10-18 21:44:53 -05:00
59d831c61f Update libflitter and enable database error logging
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-18 21:31:46 -05:00
fac3431375 Add api authorization logging
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-18 21:07:42 -05:00
7c8a05aa4f Update libflitter
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-10-18 21:00:59 -05:00
32 changed files with 207 additions and 58 deletions

35
app/assets/error-log.js Normal file
View File

@@ -0,0 +1,35 @@
window.COREID_ERROR_LOG_URL = window.COREID_ERROR_LOG_URL || '/api/v1/log-error'
async function logError(error) {
try {
await fetch(window.COREID_ERROR_LOG_URL, {
method: 'POST',
cache: 'no-cache',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
full_url: window.location.href,
trace: [
error.name + ': ' + error.message,
error.stack,
].join('\n')
}),
})
} catch (e) {}
}
;(function() {
var old_onerror = window.onerror
window.onerror = function(msg, src, line, col, error) {
logError(error).then(function() {
if ( typeof old_onerror === 'function' ) {
try {
old_onerror(msg, src, line, col, error)
} catch(e) {}
}
})
}
})()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -18,6 +18,11 @@ class CoreIDAdapter {
expiresAt = new Date(Date.now() + (expiresIn * 1000))
}
if ( payload.uid ) {
payload.originalUid = payload.uid
payload.uid = payload.uid.toLowerCase()
}
await this.coll().updateOne(
{ _id },
{ $set: { payload, ...(expiresAt ? { expiresAt } : undefined) } },
@@ -34,6 +39,11 @@ class CoreIDAdapter {
).limit(1).next()
if (!result) return undefined
if ( result?.payload?.originalUid ) {
result.payload.uid = result.payload.originalUid
}
return result.payload
}
@@ -49,11 +59,16 @@ class CoreIDAdapter {
async findByUid(uid) {
const result = await this.coll().find(
{ 'payload.uid': uid },
{ 'payload.uid': uid.toLowerCase() },
{ payload: 1 },
).limit(1).next()
if (!result) return undefined
if ( result?.payload?.originalUid ) {
result.payload.uid = result.payload.originalUid
}
return result.payload
}

View File

@@ -43,7 +43,7 @@ class FlitterProfileMapper {
getClaims() {
const claims = {}
claims[this.map.nameIdentifier] = this.user.uid
claims[this.map.nameIdentifier] = this.user.uid.toLowerCase()
claims[this.map.email] = this.user.email
claims[this.map.name] = `${this.user.first_name} ${this.user.last_name}`
claims[this.map.givenname] = this.user.first_name
@@ -54,7 +54,7 @@ class FlitterProfileMapper {
}
getNameIdentifier() {
return { nameIdentifier: this.user.uid }
return { nameIdentifier: this.user.uid.toLowerCase() }
}
}

View File

@@ -29,6 +29,12 @@ class Home extends Controller {
async tmpl(req, res) {
return res.page('tmpl', {...this.Vue.data(), ...this.Vue.session(req)})
}
async log_front_end_error(req, res, next) {
const FrontEndError = this.models.get('FrontEndError')
await FrontEndError.log(req)
return res.api()
}
}
module.exports = Home

View File

@@ -119,14 +119,12 @@ class OpenIDController extends Controller {
uid, prompt, params, session,
} = await this.openid_connect.provider.interactionDetails(req, res)
console.log({uid, prompt, params, session})
const name = prompt.name
if ( typeof this[name] !== 'function' ) {
return this.fail(res, 'Sorry, something has gone wrong.')
}
return this[name](req, res, { uid, prompt, params, session })
return this[name](req, res, { uid: uid.toLowerCase(), prompt, params, session })
}
async consent(req, res, { uid, prompt, params, session }) {
@@ -142,13 +140,13 @@ class OpenIDController extends Controller {
const Policy = this.models.get('iam:Policy')
const application = await Application.findOne({ openid_client_ids: params.client_id })
if ( !application ) {
this.output.warning('IAM Denial!')
this.output.warn('IAM Denial!')
return this.Vue.auth_message(res, {
message: req.T('saml.no_access').replace('APP_NAME', 'this application'),
next_destination: '/dash',
})
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
this.output.warning('IAM Denial!')
this.output.warn('IAM Denial!')
return this.Vue.auth_message(res, {
message: req.T('saml.no_access').replace('APP_NAME', application.name),
next_destination: '/dash',
@@ -172,7 +170,7 @@ class OpenIDController extends Controller {
{
text: req.T('common.grant'),
action: 'redirect',
next: `/openid/interaction/${uid}/grant`,
next: `/openid/interaction/${uid.toLowerCase()}/grant`,
},
],
})
@@ -180,7 +178,7 @@ class OpenIDController extends Controller {
}
async login(req, res, { uid, prompt, params, session }) {
return res.redirect(`/openid/interaction/${uid}/start-session`)
return res.redirect(`/openid/interaction/${uid.toLowerCase()}/start-session`)
}
/**
@@ -202,13 +200,13 @@ class OpenIDController extends Controller {
const Policy = this.models.get('iam:Policy')
const application = await Application.findOne({ openid_client_ids: params.client_id })
if ( !application ) {
this.output.warning('IAM Denial!')
this.output.warn('IAM Denial!')
return this.Vue.auth_message(res, {
message: req.T('saml.no_access').replace('APP_NAME', 'this application'),
next_destination: '/dash',
})
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
this.output.warning('IAM Denial!')
this.output.warn('IAM Denial!')
return this.Vue.auth_message(res, {
message: req.T('saml.no_access').replace('APP_NAME', application.name),
next_destination: '/dash',
@@ -238,13 +236,13 @@ class OpenIDController extends Controller {
const Policy = this.models.get('iam:Policy')
const application = await Application.findOne({ openid_client_ids: params.client_id })
if ( !application ) {
this.output.warning('IAM Denial!')
this.output.warn('IAM Denial!')
return this.Vue.auth_message(res, {
message: req.T('saml.no_access').replace('APP_NAME', 'this application'),
next_destination: '/dash',
})
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
this.output.warning('IAM Denial!')
this.output.warn('IAM Denial!')
return this.Vue.auth_message(res, {
message: req.T('saml.no_access').replace('APP_NAME', application.name),
next_destination: '/dash',

View File

@@ -71,7 +71,7 @@ class AuthController extends Controller {
const user = new User({
first_name: req.body.first_name,
last_name: req.body.last_name,
uid: req.body.uid,
uid: req.body.uid.toLowerCase(),
email: req.body.email,
trap: 'password_reset', // Force user to reset password
})
@@ -297,7 +297,7 @@ class AuthController extends Controller {
.api()
const user = new User({
uid: req.body.uid,
uid: req.body.uid.toLowerCase(),
email: req.body.email,
first_name: req.body.first_name,
last_name: req.body.last_name,
@@ -417,7 +417,7 @@ class AuthController extends Controller {
user.first_name = req.body.first_name
user.last_name = req.body.last_name
user.uid = req.body.uid
user.uid = req.body.uid.toLowerCase()
user.email = req.body.email
if ( req.body.tagline )
@@ -493,7 +493,7 @@ class AuthController extends Controller {
if ( is_valid ) {
const User = this.models.get('auth:User')
const user = await User.findOne({uid: req.body.username})
const user = await User.findOne({uid: req.body.username.toLowerCase()})
if ( !user || !user.can_login ) is_valid = false
}
@@ -511,7 +511,7 @@ class AuthController extends Controller {
const data = {}
if ( req.body.username ) {
const existing_user = await User.findOne({
uid: req.body.username,
uid: req.body.username.toLowerCase(),
})
data.username_taken = !!existing_user
@@ -544,7 +544,8 @@ class AuthController extends Controller {
.message(req.T('auth.unable_to_complete'))
.api({ errors })
const login_args = await flitter.get_login_args(req.body)
const [username, ...other_args] = await flitter.get_login_args(req.body)
const login_args = [username.toLowerCase(), ...other_args]
const user = await flitter.login.apply(flitter, login_args)
if ( !user )

View File

@@ -96,7 +96,7 @@ class LDAPController extends Controller {
// Make sure the uid is free
const User = this.models.get('auth:User')
const existing_user = await User.findOne({ uid: req.body.uid })
const existing_user = await User.findOne({ uid: req.body.uid.toLowerCase() })
if ( existing_user )
return res.status(400)
.message(req.T('api.user_already_exists'))
@@ -113,7 +113,7 @@ class LDAPController extends Controller {
// Create the client
const Client = this.models.get('ldap:Client')
const client = await Client.create({
uid: req.body.uid,
uid: req.body.uid.toLowerCase(),
password: req.body.password,
name: req.body.name,
})
@@ -210,16 +210,16 @@ class LDAPController extends Controller {
}
// Update the uid
if ( req.body.uid !== user.uid ) {
if ( req.body.uid.toLowerCase() !== user.uid ) {
// Make sure the UID is free
const User = this.models.get('auth:User')
const existing_user = await User.findOne({ uid: req.body.uid })
const existing_user = await User.findOne({ uid: req.body.uid.toLowerCase() })
if ( existing_user )
return res.status(400)
.message(req.T('api.user_already_exists'))
.api()
user.uid = req.body.uid
user.uid = req.body.uid.toLowerCase()
}
// Update the password

View File

@@ -8,7 +8,7 @@ const Oauth2Controller = require('flitter-auth/controllers/Oauth2')
*/
class Oauth2 extends Oauth2Controller {
static get services() {
return [...super.services, 'Vue', 'configs', 'models']
return [...super.services, 'Vue', 'configs', 'models', 'output']
}
async authorize_post(req, res, next) {
@@ -18,6 +18,24 @@ class Oauth2 extends Oauth2Controller {
const StarshipClient = this.models.get('oauth:Client')
const starship_client = await StarshipClient.findOne({ active: true, uuid: client.clientID })
// Make sure the user has IAM access before proceeding
const Application = this.models.get('Application')
const Policy = this.models.get('iam:Policy')
const application = await Application.findOne({ oauth_client_ids: starship_client.id })
if ( !application ) {
this.output.warn('IAM Denial!')
return this.Vue.auth_message(res, {
message: req.T('saml.no_access').replace('APP_NAME', application.name),
next_destination: '/dash',
})
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
this.output.warn('IAM Denial!')
return this.Vue.auth_message(res, {
message: req.T('saml.no_access').replace('APP_NAME', application.name),
next_destination: '/dash',
})
}
req.user.authorize(starship_client)
await req.user.save()
return super.authorize_post(req, res, next)
@@ -31,6 +49,24 @@ class Oauth2 extends Oauth2Controller {
const StarshipClient = this.models.get('oauth:Client')
const starship_client = await StarshipClient.findOne({ active: true, uuid: client.clientID })
// Make sure the user has IAM access before proceeding
const Application = this.models.get('Application')
const Policy = this.models.get('iam:Policy')
const application = await Application.findOne({ oauth_client_ids: starship_client.id })
if ( !application ) {
this.output.warn('IAM Denial!')
return this.Vue.auth_message(res, {
message: req.T('saml.no_access').replace('APP_NAME', application.name),
next_destination: '/dash',
})
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
this.output.warn('IAM Denial!')
return this.Vue.auth_message(res, {
message: req.T('saml.no_access').replace('APP_NAME', application.name),
next_destination: '/dash',
})
}
if ( req.user.has_authorized(starship_client) ) {
return this.Vue.invoke_action(res, {
text: 'Grant Access',

View File

@@ -67,7 +67,7 @@ class SAMLController extends Controller {
key: await this.saml.private_key(),
protocolBinding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
clearIdPSession: done => {
this.output.info(`${req.T('saml.clear_idp_session')} ${req.user.uid}`)
this.output.info(`${req.T('saml.clear_idp_session')} ${req.user.uid.toLowerCase()}`)
req.saml.participants.clear().then(async () => {
if ( this.saml.config().slo.end_coreid_session ) {
await req.user.logout(req)

View File

@@ -50,7 +50,7 @@ class LDAPController extends Injectable {
const item = await this.get_resource_from_dn(req.dn)
if ( !item ) {
this.output.debug(`Bind failure: ${req.dn} not found`)
return next(new LDAP.NoSuchObject())
return next(new LDAP.NoSuchObjectError())
}
// If the object is can-able, make sure it can bind

View File

@@ -52,7 +52,7 @@ class UsersController extends LDAPController {
first_name: req_data.cn ? req_data.cn[0] : '',
last_name: req_data.sn ? req_data.sn[0] : '',
email: req_data.mail ? req_data.mail[0] : '',
username: req_data.uid ? req_data.uid[0] : '',
username: req_data.uid ? req_data.uid[0].toLowerCase() : '',
password: req_data.userpassword ? req_data.userpassword[0] : '',
}
@@ -299,6 +299,7 @@ class UsersController extends LDAPController {
// Make sure the user is of appropriate scope
if ( req.dn.equals(user.dn) || req.dn.parentOf(user.dn) ) {
this.output.debug(await user.to_ldap())
this.output.debug(`Matches sub scope. Matches filter? ${req.filter.matches(await user.to_ldap(iam_targets))}`)
// Check if filter matches
@@ -326,7 +327,7 @@ class UsersController extends LDAPController {
try {
if ( typeof dn === 'string' ) dn = LDAP.parseDN(dn)
return dn.rdns[0].attrs[uid_field].value
return dn.rdns[0].attrs[uid_field].value.toLowerCase()
} catch (e) {}
}
@@ -334,7 +335,7 @@ class UsersController extends LDAPController {
const uid = this.get_uid_from_dn(dn)
if ( uid ) {
const User = this.models.get('auth:User')
return User.findOne({uid, ldap_visible: true})
return User.findOne({uid: uid.toLowerCase(), ldap_visible: true})
}
}
}

View File

@@ -0,0 +1,29 @@
const { Model } = require('flitter-orm')
class FrontEndErrorModel extends Model {
static get schema() {
return {
user_agent: String,
logged_at: { type: Date, default: () => new Date },
user_id: String,
session_id: String,
full_url: String,
trace: String,
}
}
static async log(request) {
const err = new this({
user_agent: request.get('user-agent'),
user_id: request?.user?.id,
session_id: request.sessionID,
full_url: request.body.full_url,
trace: request.body.trace,
})
await err.save()
return err
}
}
module.exports = exports = FrontEndErrorModel

View File

@@ -173,7 +173,7 @@ class User extends AuthUser {
const Policy = this.models.get('iam:Policy')
const ldap_data = {
uid: this.uid,
uid: this.uid.toLowerCase(),
uuid: this.uuid,
cn: this.first_name,
sn: this.last_name,
@@ -213,7 +213,7 @@ class User extends AuthUser {
}
get dn() {
return LDAP.parseDN(`uid=${this.uid},${this.ldap_server.auth_dn().format(this.configs.get('ldap:server.format'))}`)
return LDAP.parseDN(`uid=${this.uid.toLowerCase()},${this.ldap_server.auth_dn().format(this.configs.get('ldap:server.format'))}`)
}
// The following are used by OpenID connect
@@ -227,15 +227,15 @@ class User extends AuthUser {
given_name: this.first_name,
locale: 'en_US', // TODO
name: `${this.first_name} ${this.last_name}`,
preferred_username: this.uid,
username: this.uid,
preferred_username: this.uid.toLowerCase(),
username: this.uid.toLowerCase(),
}
}
static async findByLogin(login) {
return this.findOne({
active: true,
uid: login,
uid: login.toLowerCase(),
})
}

View File

@@ -118,7 +118,7 @@ class PolicyModel extends Model {
if ( this.entity_type === 'user' ) {
const User = this.models.get('auth:User')
const user = await User.findById(this.entity_id)
entity_display = `User: ${user.last_name}, ${user.first_name} (${user.uid})`
entity_display = `User: ${user.last_name}, ${user.first_name} (${user.uid.toLowerCase()})`
} else if ( this.entity_type === 'group' ) {
const Group = this.models.get('auth:Group')
const group = await Group.findById(this.entity_id)

View File

@@ -19,7 +19,7 @@ class ClientModel extends Model {
const user = new User({
first_name: name,
last_name: '(LDAP Agent)',
uid,
uid: uid.toLowerCase(),
roles: ['ldap_client'],
})
@@ -58,7 +58,7 @@ class ClientModel extends Model {
id: this.id,
name: this.name,
user_id: user.id,
uid: user.uid,
uid: user.uid.toLowerCase(),
last_invocation: this.last_invocation,
permissions: [...user.permissions, ...role_permissions],
}

View File

@@ -17,7 +17,7 @@ class SessionParticipantStore extends Injectable {
async issue({ service_provider }) {
const sp = new this.SessionParticipant({
service_provider_id: service_provider.id,
name_id: this.request.user.uid,
name_id: this.request.user.uid.toLowerCase(),
// session_index: this.get_index(),
slo_url: service_provider.slo_url,
// TODO sp_cert,

View File

@@ -8,23 +8,31 @@ class PermissionMiddleware extends Middleware {
async test(req, res, next, { check }) {
const Policy = this.models.get('iam:Policy')
if ( !req.additional_api_log_data ) req.additional_api_log_data = {}
req.additional_api_log_data.permission_check = check
// If the request was authorized using an OAuth2 bearer token,
// make sure the associated client has permission to access this endpoint.
if ( req?.oauth?.client ) {
if ( !req.oauth.client.can(check) ) {
const reason = 'oauth-permission-fail'
await this.activity.api_access_denial({
const fail_activity = await this.activity.api_access_denial({
req,
reason,
check,
oauth_client_id: req.oauth.client.uuid,
})
req.additional_api_log_data.permission_check_succeeded = false
req.additional_api_log_data.permission_check_activity_id = fail_activity.id
return res.status(401)
.message('Insufficient permissions (OAuth2 Client).')
.api()
}
req.additional_api_log_data.permission_check_succeeded = true
// If the oauth2 client has this permission, then allow the request to continue,
// even if the user does not.
// OAuth2Clients need to be able to query users via the API.
@@ -38,13 +46,18 @@ class PermissionMiddleware extends Middleware {
if ( policy_denied || (!req.user.can(check) && !policy_access) ) {
// Record the failed API access
const reason = policy_denied ? 'iam-denial' : (!req.user.can(check) ? 'user-permission-fail' : 'iam-not-granted')
await this.activity.api_access_denial({ req, reason, check })
const fail_activity = await this.activity.api_access_denial({ req, reason, check })
req.additional_api_log_data.permission_check_succeeded = false
req.additional_api_log_data.permission_check_reason = reason
req.additional_api_log_data.permission_check_activity_id = fail_activity.id
return res.status(401)
.message('Insufficient permissions.')
.api()
}
req.additional_api_log_data.permission_check_succeeded = true
return next()
}
}

View File

@@ -6,14 +6,21 @@ class APIRouteMiddleware extends Middleware {
}
async test(req, res, next, { allow_token = true, allow_user = true }) {
if ( !req.additional_api_log_data ) req.additional_api_log_data = {}
// First, check if there is a user in the session.
if ( allow_user && req.user ) {
req.additional_api_log_data.authorized_by = 'user'
return next()
} else if ( allow_token ) {
if ( !req.oauth ) req.oauth = {}
req.additional_api_log_data.attempted_token_auth = true
return req.app.oauth2.authorise()(req, res, async e => {
if ( e ) return next(e)
req.additional_api_log_data.authorized_by = 'token'
// Look up the OAuth2 client an inject it into the route
if ( req.user && req.user.id ) {
const User = this.models.get('auth:User')
@@ -44,6 +51,9 @@ class APIRouteMiddleware extends Middleware {
.message('This OAuth2 client is no longer authorized.')
.api()
req.additional_api_log_data.token_client_id = client.uuid
req.additional_api_log_data.token = bearer
req.oauth.token = token
req.oauth.client = client
} else

View File

@@ -59,6 +59,10 @@ const index = {
'middleware::auth:GuestOnly',
'controller::api:v1:Password.request_reset',
],
'/api/v1/log-error': [
'controller::Home.log_front_end_error'
],
},
}

View File

@@ -10,7 +10,7 @@ class MFAService extends Service {
secret(user) {
return speakeasy.generateSecret({
length: this.configs.get('auth.mfa.secret_length') ?? 20,
name: `${this.configs.get('app.name')} (${user.uid})`,
name: `${this.configs.get('app.name')} (${user.uid.toLowerCase()})`,
})
}

View File

@@ -25,7 +25,7 @@ class VueService extends Service {
user: {
first_name: req.user.first_name,
last_name: req.user.last_name,
username: req.user.uid,
username: req.user.uid.toLowerCase(),
email: req.user.email,
tagline: req.user.tagline,
user_id: req.user.id,

View File

@@ -36,6 +36,7 @@ class ActivityService extends Service {
}
await activity.save()
return activity
}
async mfa_enable({ req }) {

View File

@@ -28,7 +28,7 @@ class OpenIDConnectUnit extends Unit {
clients: [],
interactions: {
interactions,
url: (ctx, interaction) => `/openid/interaction/${ctx.oidc.uid}`,
url: (ctx, interaction) => `/openid/interaction/${ctx.oidc.uid.toLowerCase()}`,
},
cookies: {
long: { signed: true, maxAge: 24 * 60 * 60 * 1000 }, // 1 day, ms

View File

@@ -10,6 +10,7 @@ class SettingsUnit extends Unit {
}
async go(app) {
Error.stackTraceLimit = 50
app.express.set('trust proxy', true)
const Setting = this.models.get('Setting')

View File

@@ -15,6 +15,7 @@ html(lang='en')
.app-container
block app
block script
script(src='/assets/error-log.js')
script(src='/assets/lib/axios/axios.min.js')
script(src='/assets/lib/jquery/jquery-3.4.1.slim.min.js')
script(src='/assets/lib/popper/popper-1.16.0.min.js')

View File

@@ -25,6 +25,8 @@ const server_config = {
include_timestamp: env("LOGGING_TIMESTAMP", false),
api_logging: env('LOG_API_RESPONSES', false),
error_logging: env('LOG_REQUEST_ERRORS', true),
},
session: {

View File

@@ -33,7 +33,7 @@
"ioredis": "^4.17.1",
"is-absolute-url": "^3.0.3",
"ldapjs": "^1.0.2",
"libflitter": "^0.55.0",
"libflitter": "^0.56.1",
"moment": "^2.24.0",
"mongodb": "^3.5.9",
"nodemailer": "^6.4.6",

View File

@@ -3235,10 +3235,10 @@ leven@^1.0.2:
resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3"
integrity sha1-kUS27ryl8dBoAWnxpncNzqYLdcM=
libflitter@^0.55.0:
version "0.55.0"
resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.55.0.tgz#9392f163950ceeda57a2a7c9cc7871672268b2f5"
integrity sha512-EM4wJbdS/5KCEPU+ylw/Z8GxseK8+HrbQNu8ooSNsDsEsmCzva8K0StK8NR50eJQQkqs6XwcuMm96Y5+X9CNTA==
libflitter@^0.56.1:
version "0.56.1"
resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.56.1.tgz#250166027b9cab727c9deb6b1fa1865428b1eafb"
integrity sha512-QikFtFRa9okKOjOio5ehpQ6hyacCoMbtOlqcXt4I7uU3lntBeP5qSbz1q3x1wUY/AdBc2k70+Eg8BcpGmBEs4Q==
dependencies:
colors "^1.3.3"
connect-mongodb-session "^2.2.0"