use oauth2 password flow for webclient
This commit is contained in:
parent
6352cb3d12
commit
b706333c85
21 changed files with 367 additions and 448 deletions
|
@ -18,6 +18,7 @@
|
|||
el-menu-item(v-if='!$auth.loggedIn' index='/login')
|
||||
i.el-icon-user
|
||||
span.hidden-xs-only {{$t('common.login')}}
|
||||
|
||||
el-submenu(v-if='$auth.loggedIn' index=3)
|
||||
template(slot='title')
|
||||
i.el-icon-user
|
||||
|
|
|
@ -48,7 +48,7 @@ export default {
|
|||
data ({ $store }) {
|
||||
return {
|
||||
title: $store.state.settings.title,
|
||||
description: $store.state.settings.description,
|
||||
description: $store.state.settings.description
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -67,15 +67,27 @@ module.exports = {
|
|||
prefix: '/api'
|
||||
},
|
||||
auth: {
|
||||
// localStorage: false, // https://github.com/nuxt-community/auth-module/issues/425
|
||||
cookie: {
|
||||
prefix: 'auth.',
|
||||
expires: 360,
|
||||
maxAge: 60 * 60 * 24 * 30
|
||||
},
|
||||
redirect: {
|
||||
login: '/login'
|
||||
login: '../login'
|
||||
},
|
||||
strategies: {
|
||||
local: {
|
||||
endpoints: {
|
||||
login: { url: '/auth/login', method: 'post', propertyName: 'token' },
|
||||
login: {
|
||||
url: '../oauth/login',
|
||||
method: 'post',
|
||||
propertyName: 'access_token',
|
||||
withCredentials: true,
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
},
|
||||
logout: false,
|
||||
user: { url: '/auth/user', method: 'get', propertyName: false }
|
||||
user: { url: '/user', method: 'get', propertyName: false }
|
||||
},
|
||||
tokenRequired: true,
|
||||
tokenType: 'Bearer'
|
||||
|
|
14
package.json
14
package.json
|
@ -56,7 +56,7 @@
|
|||
"@nuxtjs/auth": "^4.8.5",
|
||||
"@nuxtjs/axios": "^5.9.3",
|
||||
"accept-language": "^3.0.18",
|
||||
"axios": "^0.19.1",
|
||||
"axios": "^0.19.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"body-parser": "^1.18.3",
|
||||
"bootstrap": "^4.4.1",
|
||||
|
@ -64,26 +64,22 @@
|
|||
"consola": "^2.11.3",
|
||||
"cookie-parser": "^1.4.4",
|
||||
"cors": "^2.8.5",
|
||||
"cross-env": "^6.0.0",
|
||||
"cross-env": "^7.0.0",
|
||||
"dayjs": "^1.8.19",
|
||||
"element-ui": "^2.13.0",
|
||||
"email-templates": "^7.0.1",
|
||||
"email-templates": "^7.0.2",
|
||||
"express": "^4.17.1",
|
||||
"express-jwt": "^5.3.1",
|
||||
"express-middleware-log": "^1.2.0",
|
||||
"express-oauth-server": "^2.0.0",
|
||||
"http-signature": "^1.3.1",
|
||||
"ics": "^2.16.0",
|
||||
"inquirer": "^7.0.3",
|
||||
"inquirer": "^7.0.4",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"less": "^3.10.3",
|
||||
"lodash": "^4.17.14",
|
||||
"mkdirp": "^0.5.1",
|
||||
"modern-css-reset": "^1.0.4",
|
||||
"mkdirp": "^1.0.3",
|
||||
"moment-timezone": "^0.5.27",
|
||||
"morgan": "^1.9.1",
|
||||
"multer": "^1.4.2",
|
||||
"node-fetch": "^2.6.0",
|
||||
"nuxt": "^2.11.0",
|
||||
"nuxt-express-module": "^0.0.11",
|
||||
"pg": "^7.17.1",
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapState } from 'vuex'
|
||||
import { mapState } from 'vuex'
|
||||
import { Message } from 'element-ui'
|
||||
import get from 'lodash/get'
|
||||
|
||||
|
@ -45,10 +45,6 @@ export default {
|
|||
this.$refs.email.focus()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['login']),
|
||||
close () {
|
||||
this.$router.replace('/')
|
||||
},
|
||||
async forgot () {
|
||||
if (!this.email) {
|
||||
Message({ message: this.$t('login.insert_email'), showClose: true, type: 'error' })
|
||||
|
@ -65,10 +61,15 @@ export default {
|
|||
e.preventDefault()
|
||||
try {
|
||||
this.loading = true
|
||||
await this.$auth.loginWith('local', { data: { email: this.email, password: this.password } })
|
||||
const data = new URLSearchParams()
|
||||
data.append('username', this.email)
|
||||
data.append('password', this.password)
|
||||
data.append('grant_type', 'password')
|
||||
data.append('client_id', 'self')
|
||||
await this.$auth.loginWith('local', { data })
|
||||
this.loading = false
|
||||
Message({ message: this.$t('login.ok'), showClose: true, type: 'success' })
|
||||
this.close()
|
||||
this.$router.replace('/')
|
||||
} catch (e) {
|
||||
Message({ message: this.$t('login.error') + this.$t(get(e, 'response.data.message', e)), showClose: true, type: 'error' })
|
||||
this.loading = false
|
||||
|
|
|
@ -8,13 +8,12 @@
|
|||
</template>
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import { Message } from 'element-ui'
|
||||
import debounce from 'lodash/debounce'
|
||||
import url from 'url'
|
||||
|
||||
export default {
|
||||
|
||||
name: 'embedEvent',
|
||||
name: 'EmbedEvent',
|
||||
data () {
|
||||
return {
|
||||
instance_hostname: '',
|
||||
|
@ -23,20 +22,7 @@ export default {
|
|||
get_instance_info: debounce(this.getInstanceInfo, 500)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getInstanceInfo () {
|
||||
const instance_url = `https://${this.instance_hostname}/api/v1/instance`
|
||||
fetch(instance_url)
|
||||
.then( ret => ret.json())
|
||||
.then(ret => {
|
||||
this.instance = ret
|
||||
this.proceed = true
|
||||
})
|
||||
.catch( e => {
|
||||
this.proceed = false
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['settings']),
|
||||
domain () {
|
||||
|
@ -45,7 +31,6 @@ export default {
|
|||
},
|
||||
couldGo () {
|
||||
// check if is mastodon
|
||||
const instance_url = `https://${this.instance_hostname}/api/v1/instance`
|
||||
this.get_instance_info()
|
||||
return true
|
||||
},
|
||||
|
@ -53,6 +38,19 @@ export default {
|
|||
// check if exists
|
||||
return `https://${this.instance_hostname}/authorize_interaction?uri=${this.settings.instance_name}@${this.domain}`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getInstanceInfo () {
|
||||
const instance_url = `https://${this.instance_hostname}/api/v1/instance`
|
||||
this.$axios.$get(instance_url)
|
||||
.then(ret => {
|
||||
this.instance = ret
|
||||
this.proceed = true
|
||||
})
|
||||
.catch(e => {
|
||||
this.proceed = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -13,19 +13,11 @@
|
|||
</template>
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import { Message, MessageBox } from 'element-ui'
|
||||
import { MessageBox } from 'element-ui'
|
||||
import url from 'url'
|
||||
|
||||
export default {
|
||||
name: 'Settings',
|
||||
async asyncData ({ $axios, params, error }) {
|
||||
try {
|
||||
const user = await $axios.$get('/auth/user')
|
||||
return { user }
|
||||
} catch (e) {
|
||||
error({ statusCode: 404, message: 'Something goes wrong...' })
|
||||
}
|
||||
},
|
||||
middleware: ['auth'],
|
||||
data () {
|
||||
return {
|
||||
|
|
|
@ -1,38 +1,35 @@
|
|||
const { Op } = require('sequelize')
|
||||
const { user: User } = require('./models')
|
||||
const debug = require('debug')('auth')
|
||||
const oauth = require('./oauth')
|
||||
|
||||
const Auth = {
|
||||
|
||||
/** isAuth middleware
|
||||
* req.user is filled in server/helper.js#initMiddleware
|
||||
*/
|
||||
async isAuth (req, res, next) {
|
||||
if (!req.user) {
|
||||
return res
|
||||
.status(403)
|
||||
.send({ message: 'Failed to authenticate token ' })
|
||||
}
|
||||
|
||||
req.user = await User.findOne({
|
||||
where: { id: { [Op.eq]: req.user.id }, is_active: true }
|
||||
})
|
||||
if (!req.user) {
|
||||
return res
|
||||
.status(403)
|
||||
.send({ message: 'Failed to authenticate token ' })
|
||||
}
|
||||
next()
|
||||
isAuth (req, res, next) {
|
||||
return oauth.oauthServer.authenticate()(req, res, next)
|
||||
},
|
||||
|
||||
/** isAdmin middleware */
|
||||
isAdmin (req, res, next) {
|
||||
if (!req.user) {
|
||||
return res
|
||||
.status(403)
|
||||
.send({ message: 'Failed to authenticate token ' })
|
||||
oauth.oauthServer.authenticate()(req, res, () => {
|
||||
req.user = res.locals.oauth.token.user
|
||||
if (req.user.is_admin) {
|
||||
next()
|
||||
} else {
|
||||
res.status(404)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
hasPerm (scope) {
|
||||
return (req, res, next) => {
|
||||
debug(scope, req.path)
|
||||
oauth.oauthServer.authenticate({ scope })(req, res, () => {
|
||||
req.user = res.locals.oauth.token.user
|
||||
next()
|
||||
})
|
||||
}
|
||||
if (req.user.is_admin && req.user.is_active) { return next() }
|
||||
return res.status(403).send({ message: 'Admin needed' })
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,23 +9,7 @@ const debug = require('debug')('controller:event')
|
|||
|
||||
const eventController = {
|
||||
|
||||
/** add a resource to event
|
||||
* @todo not used anywhere, should we use with webmention?
|
||||
* @todo should we use this for roply coming from fediverse?
|
||||
*/
|
||||
// async addComment (req, res) {
|
||||
// // comments could be added to an event or to another comment
|
||||
// let event = await Event.findOne({ where: { activitypub_id: { [Op.eq]: req.body.id } } })
|
||||
// if (!event) {
|
||||
// const comment = await Resource.findOne({ where: { activitypub_id: { [Op.eq]: req.body.id } }, include: Event })
|
||||
// event = comment.event
|
||||
// }
|
||||
// const comment = new Comment(req.body)
|
||||
// event.addComment(comment)
|
||||
// res.json(comment)
|
||||
// },
|
||||
|
||||
async getMeta (req, res) {
|
||||
async _getMeta () {
|
||||
const places = await Place.findAll({
|
||||
order: [[Sequelize.literal('weigth'), 'DESC']],
|
||||
attributes: {
|
||||
|
@ -44,7 +28,11 @@ const eventController = {
|
|||
}
|
||||
})
|
||||
|
||||
res.json({ tags, places })
|
||||
return { places, tags }
|
||||
},
|
||||
|
||||
async getMeta (req, res) {
|
||||
res.json(await eventController._getMeta())
|
||||
},
|
||||
|
||||
async getNotifications (event, action) {
|
||||
|
@ -197,131 +185,113 @@ const eventController = {
|
|||
res.sendStatus(200)
|
||||
},
|
||||
|
||||
async addRecurrent (start, places, where_tags, limit) {
|
||||
const where = {
|
||||
is_visible: true,
|
||||
recurrent: { [Op.ne]: null }
|
||||
// placeId: places
|
||||
}
|
||||
// async addRecurrent (start, places, where_tags, limit) {
|
||||
// const where = {
|
||||
// is_visible: true,
|
||||
// recurrent: { [Op.ne]: null }
|
||||
// // placeId: places
|
||||
// }
|
||||
|
||||
const events = await Event.findAll({
|
||||
where,
|
||||
limit,
|
||||
attributes: {
|
||||
exclude: ['slug', 'likes', 'boost', 'userId', 'is_visible', 'description', 'createdAt', 'updatedAt', 'placeId']
|
||||
},
|
||||
order: ['start_datetime', [Tag, 'weigth', 'DESC']],
|
||||
include: [
|
||||
{ model: Resource, required: false, attributes: ['id'] },
|
||||
{ model: Tag, ...where_tags, attributes: ['tag'], through: { attributes: [] } },
|
||||
{ model: Place, required: false, attributes: ['id', 'name', 'address'] }
|
||||
]
|
||||
})
|
||||
// const events = await Event.findAll({
|
||||
// where,
|
||||
// limit,
|
||||
// attributes: {
|
||||
// exclude: ['slug', 'likes', 'boost', 'userId', 'is_visible', 'description', 'createdAt', 'updatedAt', 'placeId']
|
||||
// },
|
||||
// order: ['start_datetime', [Tag, 'weigth', 'DESC']],
|
||||
// include: [
|
||||
// { model: Resource, required: false, attributes: ['id'] },
|
||||
// { model: Tag, ...where_tags, attributes: ['tag'], through: { attributes: [] } },
|
||||
// { model: Place, required: false, attributes: ['id', 'name', 'address'] }
|
||||
// ]
|
||||
// })
|
||||
|
||||
debug(`Found ${events.length} recurrent events`)
|
||||
let allEvents = []
|
||||
_.forEach(events, e => {
|
||||
allEvents = allEvents.concat(eventController.createEventsFromRecurrent(e.get(), start))
|
||||
})
|
||||
// let allEvents = []
|
||||
// _.forEach(events, e => {
|
||||
// allEvents = allEvents.concat(eventController.createEventsFromRecurrent(e.get(), start))
|
||||
// })
|
||||
|
||||
debug(`Created ${allEvents.length} events`)
|
||||
return allEvents
|
||||
},
|
||||
// return allEvents
|
||||
// },
|
||||
|
||||
// build singular events from a recurrent pattern
|
||||
createEventsFromRecurrent (e, start, dueTo = null) {
|
||||
const events = []
|
||||
const recurrent = JSON.parse(e.recurrent)
|
||||
if (!recurrent.frequency) { return false }
|
||||
if (!dueTo) {
|
||||
dueTo = moment.unix(start).add(2, 'month')
|
||||
}
|
||||
let cursor = moment.unix(start).startOf('week')
|
||||
const start_date = moment.unix(e.start_datetime)
|
||||
const duration = moment.unix(e.end_datetime).diff(start_date, 's')
|
||||
const frequency = recurrent.frequency
|
||||
const days = recurrent.days
|
||||
const type = recurrent.type
|
||||
// // build singular events from a recurrent pattern
|
||||
// createEventsFromRecurrent (e, start, dueTo = null) {
|
||||
// const events = []
|
||||
// const recurrent = JSON.parse(e.recurrent)
|
||||
// if (!recurrent.frequency) { return false }
|
||||
// if (!dueTo) {
|
||||
// dueTo = start.add(2, 'month')
|
||||
// }
|
||||
// let cursor = start.startOf('week')
|
||||
// const start_date = moment.unix(e.start_datetime)
|
||||
// const duration = moment.unix(e.end_datetime).diff(start_date, 's')
|
||||
// const frequency = recurrent.frequency
|
||||
// const days = recurrent.days
|
||||
// const type = recurrent.type
|
||||
|
||||
// default frequency is '1d' => each day
|
||||
const toAdd = { n: 1, unit: 'day' }
|
||||
// // default frequency is '1d' => each day
|
||||
// const toAdd = { n: 1, unit: 'day' }
|
||||
|
||||
// // each week or 2 (search for the first specified day)
|
||||
// if (frequency === '1w' || frequency === '2w') {
|
||||
// cursor.add(days[0] - 1, 'day')
|
||||
// if (frequency === '2w') {
|
||||
// const nWeeks = cursor.diff(e.start_datetime, 'w') % 2
|
||||
// if (!nWeeks) { cursor.add(1, 'week') }
|
||||
// }
|
||||
// toAdd.n = Number(frequency[0])
|
||||
// toAdd.unit = 'week'
|
||||
// // cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
|
||||
// }
|
||||
|
||||
// each week or 2 (search for the first specified day)
|
||||
if (frequency === '1w' || frequency === '2w') {
|
||||
cursor.add(days[0] - 1, 'day')
|
||||
if (frequency === '2w') {
|
||||
const nWeeks = cursor.diff(e.start_datetime, 'w') % 2
|
||||
if (!nWeeks) { cursor.add(1, 'week') }
|
||||
}
|
||||
toAdd.n = Number(frequency[0])
|
||||
toAdd.unit = 'week'
|
||||
// cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
|
||||
}
|
||||
|
||||
cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
|
||||
// // each month or 2
|
||||
// if (frequency === '1m' || frequency === '2m') {
|
||||
// // find first match
|
||||
// toAdd.n = 1
|
||||
// toAdd.unit = 'month'
|
||||
// if (type === 'weekday') {
|
||||
|
||||
// each month or 2
|
||||
if (frequency === '1m' || frequency === '2m') {
|
||||
// find first match
|
||||
toAdd.n = 1
|
||||
toAdd.unit = 'month'
|
||||
if (type === 'weekday') {
|
||||
// } else if (type === 'ordinal') {
|
||||
|
||||
} else if (type === 'ordinal') {
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
// // add event at specified frequency
|
||||
// while (true) {
|
||||
// const first_event_of_week = cursor.clone()
|
||||
// days.forEach(d => {
|
||||
// if (type === 'ordinal') {
|
||||
// cursor.date(d)
|
||||
// } else {
|
||||
// cursor.day(d - 1)
|
||||
// }
|
||||
// if (cursor.isAfter(dueTo) || cursor.isBefore(start)) { return }
|
||||
// e.start_datetime = cursor.unix()
|
||||
// e.end_datetime = e.start_datetime + duration
|
||||
// events.push(Object.assign({}, e))
|
||||
// })
|
||||
// if (cursor.isAfter(dueTo)) { break }
|
||||
// cursor = first_event_of_week.add(toAdd.n, toAdd.unit)
|
||||
// cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
|
||||
// }
|
||||
|
||||
// add event at specified frequency
|
||||
while (true) {
|
||||
const first_event_of_week = cursor.clone()
|
||||
days.forEach(d => {
|
||||
if (type === 'ordinal') {
|
||||
cursor.date(d)
|
||||
} else {
|
||||
cursor.day(d - 1)
|
||||
}
|
||||
if (cursor.isAfter(dueTo) || cursor.isBefore(start)) { return }
|
||||
e.start_datetime = cursor.unix()
|
||||
e.end_datetime = e.start_datetime + duration
|
||||
events.push(Object.assign({}, e))
|
||||
})
|
||||
if (cursor.isAfter(dueTo)) { break }
|
||||
cursor = first_event_of_week.add(toAdd.n, toAdd.unit)
|
||||
cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
|
||||
}
|
||||
// return events
|
||||
// },
|
||||
|
||||
return events
|
||||
},
|
||||
|
||||
/**
|
||||
* Select events based on params
|
||||
*/
|
||||
async select (req, res) {
|
||||
const start = req.query.start || moment().unix()
|
||||
const limit = req.query.limit || 100
|
||||
const show_recurrent = req.query.show_recurrent || true
|
||||
const filter_tags = req.query.tags || ''
|
||||
const filter_places = req.query.places || ''
|
||||
|
||||
debug(`select limit:${limit} rec:${show_recurrent} tags:${filter_tags} places:${filter_places}`)
|
||||
let where_tags = {}
|
||||
async _select (start = moment.unix(), limit = 100, show_recurrent = true) {
|
||||
const where = {
|
||||
// confirmed event only
|
||||
is_visible: true,
|
||||
start_datetime: { [Op.gt]: start },
|
||||
recurrent: null
|
||||
start_datetime: { [Op.gt]: start }
|
||||
}
|
||||
|
||||
if (filter_tags) {
|
||||
where_tags = { where: { tag: filter_tags.split(',') } }
|
||||
if (!show_recurrent) {
|
||||
where.recurrent = null
|
||||
}
|
||||
|
||||
if (filter_places) {
|
||||
where.placeId = filter_places.split(',')
|
||||
}
|
||||
|
||||
let events = await Event.findAll({
|
||||
const events = await Event.findAll({
|
||||
where,
|
||||
limit,
|
||||
attributes: {
|
||||
|
@ -331,79 +301,76 @@ const eventController = {
|
|||
order: ['start_datetime', [Tag, 'weigth', 'DESC']],
|
||||
include: [
|
||||
{ model: Resource, required: false, attributes: ['id'] },
|
||||
{ model: Tag, ...where_tags, attributes: ['tag'], through: { attributes: [] } },
|
||||
{ model: Tag, attributes: ['tag'], required: false, through: { attributes: [] } },
|
||||
{ model: Place, required: false, attributes: ['id', 'name', 'address'] }
|
||||
]
|
||||
})
|
||||
|
||||
let recurrentEvents = []
|
||||
events = _.map(events, e => e.get())
|
||||
if (show_recurrent) {
|
||||
recurrentEvents = await eventController.addRecurrent(start, where.placeId, where_tags, limit)
|
||||
events = _.concat(events, recurrentEvents)
|
||||
}
|
||||
|
||||
// flat tags
|
||||
events = _(events).map(e => {
|
||||
e.tags = e.tags.map(t => t.tag)
|
||||
return _(events).map(e => {
|
||||
e = e.get()
|
||||
e.tags = e.tags ? e.tags.map(t => t && t.tag) : []
|
||||
return e
|
||||
})
|
||||
// allEvents.sort((a,b) => a.start_datetime-b.start_datetime)
|
||||
res.json(events.sort((a, b) => a.start_datetime - b.start_datetime))
|
||||
// res.json(recurrentEvents)
|
||||
}
|
||||
},
|
||||
|
||||
// async getAll (req, res) {
|
||||
// // this is due how v-calendar shows dates
|
||||
// const start = moment()
|
||||
// .year(req.params.year)
|
||||
// .month(req.params.month)
|
||||
// .startOf('month')
|
||||
// .startOf('week')
|
||||
/**
|
||||
* Select events based on params
|
||||
*/
|
||||
async select (req, res) {
|
||||
const start = req.query.start || moment().unix()
|
||||
const limit = req.query.limit || 100
|
||||
const show_recurrent = req.query.show_recurrent || true
|
||||
res.json(await eventController._select(start, limit, show_recurrent))
|
||||
// const filter_tags = req.query.tags || ''
|
||||
// const filter_places = req.query.places || ''
|
||||
|
||||
// let end = moment()
|
||||
// .year(req.params.year)
|
||||
// .month(req.params.month)
|
||||
// .endOf('month')
|
||||
// debug(`select limit:${limit} rec:${show_recurrent} tags:${filter_tags} places:${filter_places}`)
|
||||
// let where_tags = {}
|
||||
// const where = {
|
||||
// // confirmed event only
|
||||
// is_visible: true,
|
||||
// start_datetime: { [Op.gt]: start },
|
||||
// recurrent: null
|
||||
// }
|
||||
|
||||
// const shownDays = end.diff(start, 'days')
|
||||
// if (shownDays <= 35) { end = end.add(1, 'week') }
|
||||
// end = end.endOf('week')
|
||||
// if (filter_tags) {
|
||||
// where_tags = { where: { tag: filter_tags.split(',') } }
|
||||
// }
|
||||
|
||||
// if (filter_places) {
|
||||
// where.placeId = filter_places.split(',')
|
||||
// }
|
||||
|
||||
// let events = await Event.findAll({
|
||||
// where: {
|
||||
// // return only confirmed events
|
||||
// is_visible: true,
|
||||
// [Op.or]: [
|
||||
// // return all recurrent events regardless start_datetime
|
||||
// { recurrent: { [Op.ne]: null } },
|
||||
|
||||
// // and events in specified range
|
||||
// { start_datetime: { [Op.between]: [start.unix(), end.unix()] } }
|
||||
// ]
|
||||
// where,
|
||||
// limit,
|
||||
// attributes: {
|
||||
// exclude: ['slug', 'likes', 'boost', 'userId', 'is_visible', 'description', 'createdAt', 'updatedAt', 'placeId']
|
||||
// // include: [[Sequelize.fn('COUNT', Sequelize.col('activitypub_id')), 'ressources']]
|
||||
// },
|
||||
// attributes: { exclude: ['createdAt', 'updatedAt', 'placeId'] },
|
||||
// order: [[Tag, 'weigth', 'DESC']],
|
||||
// order: ['start_datetime', [Tag, 'weigth', 'DESC']],
|
||||
// include: [
|
||||
// { model: Resource, required: false, attributes: ['id'] },
|
||||
// { model: Tag, required: false },
|
||||
// { model: Tag, ...where_tags, attributes: ['tag'], through: { attributes: [] } },
|
||||
// { model: Place, required: false, attributes: ['id', 'name', 'address'] }
|
||||
// ]
|
||||
// })
|
||||
// events = events.map(e => e.get()).map(e => {
|
||||
|
||||
// let recurrentEvents = []
|
||||
// events = _.map(events, e => e.get())
|
||||
// if (show_recurrent) {
|
||||
// recurrentEvents = await eventController.addRecurrent(moment.unix(start), where.placeId, where_tags, limit)
|
||||
// events = _.concat(events, recurrentEvents)
|
||||
// }
|
||||
|
||||
// // flat tags
|
||||
// events = _(events).map(e => {
|
||||
// e.tags = e.tags.map(t => t.tag)
|
||||
// return e
|
||||
// })
|
||||
|
||||
// let allEvents = events.filter(e => !e.recurrent || e.recurrent.length === 0)
|
||||
// events.filter(e => e.recurrent && e.recurrent.length).forEach(e => {
|
||||
// const events = createEventsFromRecurrent(e, end)
|
||||
// if (events) { allEvents = allEvents.concat(events) }
|
||||
// })
|
||||
|
||||
// // allEvents.sort((a,b) => a.start_datetime-b.start_datetime)
|
||||
// res.json(allEvents.sort((a, b) => a.start_datetime - b.start_datetime))
|
||||
// }
|
||||
// res.json(events.sort((a, b) => a.start_datetime - b.start_datetime))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -76,12 +76,12 @@ const oauthController = {
|
|||
* */
|
||||
async getAccessToken (accessToken) {
|
||||
const oauth_token = await OAuthToken.findByPk(accessToken,
|
||||
{ include: [User, { model: OAuthClient, as: 'client' }], nest: true, raw: true })
|
||||
{ include: [User, { model: OAuthClient, as: 'client' }] })
|
||||
return oauth_token
|
||||
},
|
||||
|
||||
/**
|
||||
* Invoked to retrieve a client using a client id or a client id/client secret combination, depending on the grant type.
|
||||
* Invoked to retrieve a client using a client id or a client id/client secret combination, depend on the grant type.
|
||||
*/
|
||||
async getClient (client_id, client_secret) {
|
||||
const client = await OAuthClient.findByPk(client_id, { raw: true })
|
||||
|
@ -89,7 +89,7 @@ const oauthController = {
|
|||
return false
|
||||
}
|
||||
|
||||
if (client) { client.grants = ['authorization_code'] }
|
||||
if (client) { client.grants = ['authorization_code', 'password'] }
|
||||
|
||||
return client
|
||||
},
|
||||
|
@ -119,11 +119,32 @@ const oauthController = {
|
|||
return oauth_code.destroy()
|
||||
},
|
||||
|
||||
async getUser (username, password) {
|
||||
const user = await User.findOne({ where: { email: username } })
|
||||
if (!user || !user.is_active) {
|
||||
return false
|
||||
}
|
||||
// check if password matches
|
||||
if (await user.comparePassword(password)) {
|
||||
return user
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
async saveAuthorizationCode (code, client, user) {
|
||||
code.userId = user.id
|
||||
code.oauthClientId = client.id
|
||||
const ret = await OAuthCode.create(code)
|
||||
return ret
|
||||
},
|
||||
|
||||
verifyScope (token, scope) {
|
||||
debug(token.user.is_admin)
|
||||
if (token.user.is_admin) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const crypto = require('crypto')
|
||||
const jwt = require('jsonwebtoken')
|
||||
const { Op } = require('sequelize')
|
||||
const jsonwebtoken = require('jsonwebtoken')
|
||||
const sanitizeHtml = require('sanitize-html')
|
||||
const config = require('config')
|
||||
const mail = require('../mail')
|
||||
|
@ -12,33 +10,6 @@ const settingsController = require('./settings')
|
|||
const debug = require('debug')('user:controller')
|
||||
|
||||
const userController = {
|
||||
async login (req, res) {
|
||||
// find the user
|
||||
const user = await User.findOne({ where: { email: req.body.email } })
|
||||
if (!user) {
|
||||
res.status(403).json({ success: false, message: 'auth.fail' })
|
||||
} else if (user) {
|
||||
if (!user.is_active) {
|
||||
res.status(403).json({ success: false, message: 'auth.not_confirmed' })
|
||||
// check if password matches
|
||||
} else if (!await user.comparePassword(req.body.password)) {
|
||||
res.status(403).json({ success: false, message: 'auth.fail' })
|
||||
} else {
|
||||
// if user is found and password is right
|
||||
// create a token
|
||||
const accessToken = jsonwebtoken.sign(
|
||||
{
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
scope: [user.is_admin ? 'admin' : 'user']
|
||||
},
|
||||
config.secret
|
||||
)
|
||||
res.json({ token: accessToken })
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async delEvent (req, res) {
|
||||
const event = await Event.findByPk(req.params.id)
|
||||
// check if event is mine (or user is admin)
|
||||
|
|
|
@ -2,7 +2,7 @@ const express = require('express')
|
|||
const multer = require('multer')
|
||||
const cors = require('cors')()
|
||||
|
||||
const { isAuth, isAdmin } = require('./auth')
|
||||
const { isAuth, isAdmin, hasPerm } = require('./auth')
|
||||
const eventController = require('./controller/event')
|
||||
const exportController = require('./controller/export')
|
||||
const userController = require('./controller/user')
|
||||
|
@ -11,7 +11,6 @@ const instanceController = require('./controller/instance')
|
|||
const apUserController = require('./controller/ap_user')
|
||||
const resourceController = require('./controller/resource')
|
||||
const oauthController = require('./controller/oauth')
|
||||
const oauth = require('./oauth')
|
||||
|
||||
const storage = require('./storage')
|
||||
const upload = multer({ storage })
|
||||
|
@ -22,10 +21,9 @@ const api = express.Router()
|
|||
api.use(express.urlencoded({ extended: false }))
|
||||
api.use(express.json())
|
||||
|
||||
// AUTH
|
||||
api.post('/auth/login', userController.login)
|
||||
api.get('/auth/user', userController.current)
|
||||
|
||||
api.get('/user', isAuth, (req, res) => res.json(res.locals.oauth.token.user))
|
||||
// api.post('/user/login', userController.login)
|
||||
// api.get('/user/logout', userController.logout)
|
||||
api.post('/user/recover', userController.forgotPassword)
|
||||
api.post('/user/check_recover_code', userController.checkRecoverCode)
|
||||
api.post('/user/recover_password', userController.updatePasswordWithRecoverCode)
|
||||
|
@ -35,12 +33,11 @@ api.post('/user/register', userController.register)
|
|||
api.post('/user', isAdmin, userController.create)
|
||||
|
||||
// update user
|
||||
api.put('/user', isAuth, userController.update)
|
||||
api.put('/user', hasPerm('user:update'), userController.update)
|
||||
|
||||
// delete user
|
||||
api.delete('/user/:id', isAdmin, userController.remove)
|
||||
|
||||
// api.delete('/user', userController.remove)
|
||||
api.delete('/user', hasPerm('user:remove'), userController.remove)
|
||||
|
||||
// get all users
|
||||
api.get('/users', isAdmin, userController.getAll)
|
||||
|
@ -52,10 +49,10 @@ api.put('/place', isAdmin, eventController.updatePlace)
|
|||
api.post('/user/event', upload.single('image'), userController.addEvent)
|
||||
|
||||
// update event
|
||||
api.put('/user/event', isAuth, upload.single('image'), userController.updateEvent)
|
||||
api.put('/user/event', hasPerm('event:write'), upload.single('image'), userController.updateEvent)
|
||||
|
||||
// remove event
|
||||
api.delete('/user/event/:id', isAuth, userController.delEvent)
|
||||
api.delete('/user/event/:id', hasPerm('event:remove'), userController.delEvent)
|
||||
|
||||
// get tags/places
|
||||
api.get('/event/meta', eventController.getMeta)
|
||||
|
@ -63,18 +60,17 @@ api.get('/event/meta', eventController.getMeta)
|
|||
// get unconfirmed events
|
||||
api.get('/event/unconfirmed', isAdmin, eventController.getUnconfirmed)
|
||||
|
||||
// add event notification
|
||||
// add event notification TODO
|
||||
api.post('/event/notification', eventController.addNotification)
|
||||
api.delete('/event/notification/:code', eventController.delNotification)
|
||||
|
||||
api.get('/settings', settingsController.getAllRequest)
|
||||
api.post('/settings', isAdmin, settingsController.setRequest)
|
||||
api.post('/settings/favicon', isAdmin, multer({ dest: 'thumb/' }).single('favicon'), settingsController.setFavicon)
|
||||
// api.get('/settings/user_locale', settingsController.getUserLocale)
|
||||
|
||||
// confirm eventtags
|
||||
api.get('/event/confirm/:event_id', isAuth, eventController.confirm)
|
||||
api.get('/event/unconfirm/:event_id', isAuth, eventController.unconfirm)
|
||||
// confirm event
|
||||
api.get('/event/confirm/:event_id', hasPerm('event:write'), eventController.confirm)
|
||||
api.get('/event/unconfirm/:event_id', hasPerm('event:write'), eventController.unconfirm)
|
||||
|
||||
// get event
|
||||
api.get('/event/:event_id.:format?', cors, eventController.get)
|
||||
|
@ -94,18 +90,11 @@ api.put('/resources/:resource_id', isAdmin, resourceController.hide)
|
|||
api.delete('/resources/:resource_id', isAdmin, resourceController.remove)
|
||||
api.get('/resources', isAdmin, resourceController.getAll)
|
||||
|
||||
api.get('/clients', isAuth, oauthController.getClients)
|
||||
api.get('/client/:client_id', isAuth, oauthController.getClient)
|
||||
api.get('/clients', hasPerm('oauth:read'), oauthController.getClients)
|
||||
api.get('/client/:client_id', hasPerm('oauth:read'), oauthController.getClient)
|
||||
api.post('/client', oauthController.createClient)
|
||||
|
||||
// api.get('/verify', oauth.oauthServer.authenticate(), (req, res) => {
|
||||
// })
|
||||
|
||||
// Handle 404
|
||||
api.use((req, res) => {
|
||||
debug('404 Page not found: %s', req.path)
|
||||
res.status(404).send('404: Page not Found')
|
||||
})
|
||||
api.use((req, res) => res.sendStatus(404))
|
||||
|
||||
// Handle 500
|
||||
api.use((error, req, res, next) => {
|
||||
|
|
|
@ -32,7 +32,7 @@ const mail = {
|
|||
updateFiles: false,
|
||||
defaultLocale: settings.locale,
|
||||
locale: settings.locale,
|
||||
locales: ['it', 'es'] // TOFIX
|
||||
locales: ['it', 'es', 'en', 'ca']
|
||||
},
|
||||
transport: config.smtp
|
||||
})
|
||||
|
|
|
@ -10,6 +10,7 @@ const oauthServer = new OAuthServer({
|
|||
useErrorHandler: true,
|
||||
continueMiddleware: false,
|
||||
debug: true,
|
||||
requireClientAuthentication: { password: false },
|
||||
authenticateHandler: {
|
||||
handle (req) {
|
||||
if (!req.user) {
|
||||
|
@ -25,9 +26,12 @@ oauth.use(express.json())
|
|||
oauth.use(express.urlencoded({ extended: false }))
|
||||
|
||||
oauth.post('/token', oauthServer.token())
|
||||
oauth.post('/login', oauthServer.token())
|
||||
|
||||
oauth.get('/authorize', oauthServer.authorize())
|
||||
|
||||
oauth.use((req, res) => res.sendStatus(404))
|
||||
|
||||
oauth.use((err, req, res, next) => {
|
||||
const error_msg = err.toString()
|
||||
debug(err)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const fetch = require('node-fetch')
|
||||
const fetch = require('axios')
|
||||
// const request = require('request')
|
||||
const crypto = require('crypto')
|
||||
const config = require('config')
|
||||
|
@ -36,6 +36,7 @@ const Helpers = {
|
|||
const signature = signer.sign(privkey)
|
||||
const signature_b64 = signature.toString('base64')
|
||||
const header = `keyId="${config.baseurl}/federation/u/${settingsController.settings.instance_name}",headers="(request-target) host date",signature="${signature_b64}"`
|
||||
try {
|
||||
const ret = await fetch(inbox, {
|
||||
headers: {
|
||||
Host: inboxUrl.hostname,
|
||||
|
@ -48,6 +49,9 @@ const Helpers = {
|
|||
body: JSON.stringify(message)
|
||||
})
|
||||
debug('sign %s => %s', ret.status, await ret.text())
|
||||
} catch (e) {
|
||||
debug('ERROR ', e.toString())
|
||||
}
|
||||
},
|
||||
|
||||
async sendEvent (event, type = 'Create') {
|
||||
|
|
|
@ -82,4 +82,10 @@ router.get('/u/:name/outbox', Users.outbox)
|
|||
router.get('/u/:name/followers', Users.followers)
|
||||
router.get('/u/:name', Users.get)
|
||||
|
||||
// Handle 404
|
||||
router.use((req, res) => {
|
||||
debug('404 Page not found: %s', req.path)
|
||||
res.status(404).send('404: Page not Found')
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
|
|
|
@ -1,27 +1,12 @@
|
|||
const settingsController = require('./api/controller/settings')
|
||||
const { user: User } = require('./api/models')
|
||||
const acceptLanguage = require('accept-language')
|
||||
const expressJwt = require('express-jwt')
|
||||
const moment = require('moment-timezone')
|
||||
const config = require('config')
|
||||
const pkg = require('../package.json')
|
||||
|
||||
const jwt = expressJwt({
|
||||
secret: config.secret,
|
||||
credentialsRequired: false,
|
||||
getToken: function fromHeaderOrQuerystring (req) {
|
||||
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
|
||||
return req.headers.authorization.split(' ')[1]
|
||||
} else if (req.cookies && req.cookies['auth._token.local']) {
|
||||
const [prefix, token] = req.cookies['auth._token.local'].split(' ')
|
||||
if (prefix === 'Bearer') { return token }
|
||||
}
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
async initMiddleware (req, res, next) {
|
||||
|
||||
async initSettings (req, res, next) {
|
||||
await settingsController.load()
|
||||
// initialize settings
|
||||
req.settings = settingsController.settings
|
||||
|
@ -40,12 +25,7 @@ module.exports = {
|
|||
req.settings.user_locale = settingsController.user_locale[req.settings.locale]
|
||||
moment.locale(req.settings.locale)
|
||||
moment.tz.setDefault(req.settings.instance_timezone)
|
||||
|
||||
// TODO: oauth
|
||||
jwt(req, res, async () => {
|
||||
if (!req.user) { return next() }
|
||||
req.user = await User.findOne({ where: { id: req.user.id, is_active: true } })
|
||||
next()
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,7 +10,10 @@ const webfinger = require('./federation/webfinger')
|
|||
const { spamFilter } = require('./federation/helpers')
|
||||
const debug = require('debug')('routes')
|
||||
const exportController = require('./api/controller/export')
|
||||
const eventController = require('./api/controller/event')
|
||||
|
||||
const helpers = require('./helpers')
|
||||
const { startOfMonth, startOfWeek, getUnixTime } = require('date-fns')
|
||||
const app = express()
|
||||
|
||||
app.use((req, res, next) => {
|
||||
|
@ -26,8 +29,7 @@ app.use('/logo.png', express.static('./static/gancio.png'))
|
|||
app.use('/media/', express.static(config.upload_path))
|
||||
|
||||
// initialize instance settings / authentication / locale
|
||||
app.use(cookieParser())
|
||||
app.use(helpers.initMiddleware)
|
||||
app.use(helpers.initSettings)
|
||||
app.use('/favicon.ico', (req, res, next) => {
|
||||
const favicon_path = req.settings.favicon || config.favicon || './assets/favicon.ico'
|
||||
return express.static(path.resolve(favicon_path))(req, res, next)
|
||||
|
@ -36,14 +38,15 @@ app.use('/favicon.ico', (req, res, next) => {
|
|||
// rss/ics/atom feed
|
||||
app.get('/feed/:type', cors(), exportController.export)
|
||||
|
||||
// api!
|
||||
app.use('/api', api)
|
||||
app.use('/oauth', oauth)
|
||||
|
||||
// federation api / activitypub / webfinger / nodeinfo
|
||||
app.use('/.well-known', webfinger)
|
||||
app.use('/federation', federation)
|
||||
|
||||
// api!
|
||||
app.use(cookieParser())
|
||||
app.use('/api', api)
|
||||
app.use('/oauth', oauth)
|
||||
|
||||
// // Handle 500
|
||||
app.use((error, req, res, next) => {
|
||||
debug('Error 500: %s', error)
|
||||
|
@ -52,5 +55,12 @@ app.use((error, req, res, next) => {
|
|||
|
||||
// remaining request goes to nuxt
|
||||
// first nuxt component is ./pages/index.vue (with ./layouts/default.vue)
|
||||
// prefill current events, tags, places (used in every path)
|
||||
app.use(async (req, res, next) => {
|
||||
const start_datetime = getUnixTime(startOfWeek(startOfMonth(new Date())))
|
||||
req.events = await eventController._select(start_datetime, 100, req.settings.recurrent_event_visible)
|
||||
req.meta = await eventController._getMeta()
|
||||
next()
|
||||
})
|
||||
|
||||
module.exports = app
|
||||
|
|
|
@ -143,9 +143,6 @@ export const mutations = {
|
|||
setLocale (state, locale) {
|
||||
state.locale = locale
|
||||
},
|
||||
setUserLocale (state, user_locale) {
|
||||
state.user_locale = user_locale
|
||||
},
|
||||
setPast (state, in_past) {
|
||||
state.in_past = in_past
|
||||
}
|
||||
|
@ -154,25 +151,14 @@ export const mutations = {
|
|||
export const actions = {
|
||||
// this method is called server side only for each request for nuxt
|
||||
// we use it to get configuration from db, set locale, etc...
|
||||
async nuxtServerInit ({ commit }, { app, store, req }) {
|
||||
if (req.user) { this.$auth.setUser(req.user) }
|
||||
nuxtServerInit ({ commit }, { req }) {
|
||||
commit('setSettings', req.settings)
|
||||
|
||||
const settings = req.settings
|
||||
commit('setSettings', settings)
|
||||
|
||||
const start_datetime = moment().startOf('month').startOf('week').unix()
|
||||
let query = `start=${start_datetime}`
|
||||
if (settings.recurrent_event_visible) {
|
||||
query += '&show_recurrent'
|
||||
}
|
||||
const events = await this.$axios.$get(`/event?${query}`)
|
||||
commit('setEvents', events)
|
||||
|
||||
const { tags, places } = await this.$axios.$get('/event/meta')
|
||||
store.commit('update', { tags, places })
|
||||
commit('setEvents', req.events)
|
||||
commit('update', req.meta)
|
||||
|
||||
// apply settings
|
||||
commit('showRecurrentEvents', settings.allow_recurrent_event && settings.recurrent_event_visible)
|
||||
commit('showRecurrentEvents', req.settings.allow_recurrent_event && req.settings.recurrent_event_visible)
|
||||
},
|
||||
async updateEvents ({ commit }, page) {
|
||||
const [month, year] = [moment().month(), moment().year()]
|
||||
|
|
114
yarn.lock
114
yarn.lock
|
@ -805,12 +805,12 @@
|
|||
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.2.tgz#1c794cd6dbf2354d1eb1ef10e0303f573e1c7222"
|
||||
integrity sha512-O4QDrx+JoGKZc6aN64L04vqa7e41tIiLU+OvKdcYaEMP97UttL0f9GIi9/0A4WAMx0uBd6SidDIhktZhgOcN8Q==
|
||||
|
||||
"@hapi/boom@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-8.0.1.tgz#13f1f2f2a3abfb0787c79e35e238c8aff6aa1661"
|
||||
integrity sha512-SnBM2GzEYEA6AGFKXBqNLWXR3uNBui0bkmklYXX1gYtevVhDTy2uakwkSauxvIWMtlANGRhzChYg95If3FWCwA==
|
||||
"@hapi/boom@^9.0.0":
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-9.0.0.tgz#28f9e77ecf2dea1fe3a8982b9d8827aa5137e33a"
|
||||
integrity sha512-D+Or4yahLq3L7D1Jf0fR1+Lgr+HPK1lej8tc6hS/fBLmK66XdpvTyKv8YUR5ls1GeQy+KGtbpKAs+ZxyzNtUyA==
|
||||
dependencies:
|
||||
"@hapi/hoek" "8.x.x"
|
||||
"@hapi/hoek" "9.x.x"
|
||||
|
||||
"@hapi/bourne@1.x.x":
|
||||
version "1.3.2"
|
||||
|
@ -822,6 +822,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.3.0.tgz#2b9db1cd00f3891005c77b3a8d608b88a6d0aa4d"
|
||||
integrity sha512-C0QL9bmgUXTSuf8nDeGrpMjtJG7tPUr8wG6/wxPbP62tGwCwQtdMSJYfESowmY4P3Hn593f+8OzNY5bckcu/LQ==
|
||||
|
||||
"@hapi/hoek@9.x.x":
|
||||
version "9.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.0.2.tgz#57597083f763eafbfdc902d16ec868aa787b24d2"
|
||||
integrity sha512-LyibKv2QnD9BPI5g2L+g85yiIPv3ajYpENGFgy4u0xCLPhXWG1Zdx29neSB8sgX0/wz6k5TMjHzTwJ6+DaBYOA==
|
||||
|
||||
"@hapi/joi@^15.1.1":
|
||||
version "15.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7"
|
||||
|
@ -839,17 +844,17 @@
|
|||
dependencies:
|
||||
"@hapi/hoek" "8.x.x"
|
||||
|
||||
"@ladjs/i18n@^3.0.1":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@ladjs/i18n/-/i18n-3.0.1.tgz#efb32d7ee11421a48dbfda2c582113bb88c11713"
|
||||
integrity sha512-/glfm9tY5Sd8L/oqnaFH1XrqfMFConHPxWPIioQ1SHrglmKOZEVFwN2Yc0zFs3Rzf9NXdTHMmsitgsyejDNtcQ==
|
||||
"@ladjs/i18n@^3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@ladjs/i18n/-/i18n-3.0.2.tgz#4021164d42f5f69910776c2ddd6349e80caf6179"
|
||||
integrity sha512-/GICRKaL8blp3xE1klDIDW1YZSw8CEqlwCn426dcagYrkv5RH+oYlWEQPRz6N0vJPeMaHk8DCFm9qppLjDOXuw==
|
||||
dependencies:
|
||||
"@hapi/boom" "^8.0.1"
|
||||
"@hapi/boom" "^9.0.0"
|
||||
boolean "3.0.0"
|
||||
country-language "^0.1.7"
|
||||
debug "^4.1.1"
|
||||
i18n "^0.8.4"
|
||||
i18n-locales "^0.0.2"
|
||||
i18n-locales "^0.0.4"
|
||||
lodash "^4.17.15"
|
||||
moment "^2.24.0"
|
||||
multimatch "^4.0.0"
|
||||
|
@ -1819,11 +1824,6 @@ async-validator@~1.8.1:
|
|||
dependencies:
|
||||
babel-runtime "6.x"
|
||||
|
||||
async@^1.5.0:
|
||||
version "1.5.2"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
|
||||
integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=
|
||||
|
||||
async@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.1.0.tgz#42b3b12ae1b74927b5217d8c0016baaf62463772"
|
||||
|
@ -1884,6 +1884,13 @@ axios@^0.19.1:
|
|||
dependencies:
|
||||
follow-redirects "1.5.10"
|
||||
|
||||
axios@^0.19.2:
|
||||
version "0.19.2"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
|
||||
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
|
||||
dependencies:
|
||||
follow-redirects "1.5.10"
|
||||
|
||||
babel-eslint@^10.0.3:
|
||||
version "10.0.3"
|
||||
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a"
|
||||
|
@ -3077,12 +3084,12 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
|
|||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
cross-env@^6.0.0:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941"
|
||||
integrity sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==
|
||||
cross-env@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.0.tgz#5a3b2ddce51ec713ea58f2fb79ce22e65b4f5479"
|
||||
integrity sha512-rV6M9ldNgmwP7bx5u6rZsTbYidzwvrwIYZnT08hSGLcQCcggofgFW+sNe7IhA1SRauPS0QuLbbX+wdNtpqE5CQ==
|
||||
dependencies:
|
||||
cross-spawn "^7.0.0"
|
||||
cross-spawn "^7.0.1"
|
||||
|
||||
cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5:
|
||||
version "6.0.5"
|
||||
|
@ -3104,7 +3111,7 @@ cross-spawn@^5.0.1:
|
|||
shebang-command "^1.2.0"
|
||||
which "^1.2.9"
|
||||
|
||||
cross-spawn@^7.0.0:
|
||||
cross-spawn@^7.0.0, cross-spawn@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14"
|
||||
integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==
|
||||
|
@ -3775,12 +3782,12 @@ elliptic@^6.0.0:
|
|||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.0"
|
||||
|
||||
email-templates@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/email-templates/-/email-templates-7.0.1.tgz#9361001fa7e6aafaa6ed55012ef79d991f2115b7"
|
||||
integrity sha512-VY5RtLO7paSYYUDiDeGTIB4ejGXSwVTOhnPEQ5ZNyU3l0XhFCCIBtybXwu7Edn17MwRjhnOjyRR5SZUAAuVqVA==
|
||||
email-templates@^7.0.2:
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/email-templates/-/email-templates-7.0.2.tgz#de7f848168b9c8bd11312c3220b2224a2fd45f73"
|
||||
integrity sha512-nPP4AlFn9QoiphyEv3eS0VQ8Z7QzzMFI6PPYxmUeXOKeTlm9arDW8PLTylw4+40mO4rAHPmtmesM53mPgZooxA==
|
||||
dependencies:
|
||||
"@ladjs/i18n" "^3.0.1"
|
||||
"@ladjs/i18n" "^3.0.2"
|
||||
"@sindresorhus/is" "^1.2.0"
|
||||
consolidate "^0.15.1"
|
||||
debug "^4.1.1"
|
||||
|
@ -4431,21 +4438,6 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2:
|
|||
dependencies:
|
||||
homedir-polyfill "^1.0.1"
|
||||
|
||||
express-jwt@^5.3.1:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/express-jwt/-/express-jwt-5.3.1.tgz#66f05c7dddb5409c037346a98b88965bb10ea4ae"
|
||||
integrity sha512-1C9RNq0wMp/JvsH/qZMlg3SIPvKu14YkZ4YYv7gJQ1Vq+Dv8LH9tLKenS5vMNth45gTlEUGx+ycp9IHIlaHP/g==
|
||||
dependencies:
|
||||
async "^1.5.0"
|
||||
express-unless "^0.3.0"
|
||||
jsonwebtoken "^8.1.0"
|
||||
lodash.set "^4.0.0"
|
||||
|
||||
express-middleware-log@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/express-middleware-log/-/express-middleware-log-1.2.0.tgz#62682021ba3b1cbfd6b081e7364ebb1fd6d5a0fb"
|
||||
integrity sha512-1G9cHlGJs4+nFphSqVduJfCzeaqHeOdpTRBAjceRRcLWeHzj9sXDYP99tNjaeHsHn3N3vlNI+vIn/lb9eYXmuw==
|
||||
|
||||
express-oauth-server@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/express-oauth-server/-/express-oauth-server-2.0.0.tgz#57b08665c1201532f52c4c02f19709238b99a48d"
|
||||
|
@ -4455,11 +4447,6 @@ express-oauth-server@^2.0.0:
|
|||
express "^4.13.3"
|
||||
oauth2-server "3.0.0"
|
||||
|
||||
express-unless@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/express-unless/-/express-unless-0.3.1.tgz#2557c146e75beb903e2d247f9b5ba01452696e20"
|
||||
integrity sha1-JVfBRudb65A+LSR/m1ugFFJpbiA=
|
||||
|
||||
express@^4.13.3, express@^4.16.3, express@^4.17.1:
|
||||
version "4.17.1"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
|
||||
|
@ -5432,10 +5419,12 @@ human-signals@^1.1.1:
|
|||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
||||
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
|
||||
|
||||
i18n-locales@^0.0.2:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/i18n-locales/-/i18n-locales-0.0.2.tgz#12e56046f1fa260e11658f4ac62f60b363479ff9"
|
||||
integrity sha512-WCaJVIfU10v0/ZNy+mG7fCUQb1o2PsM7tNf1dUg0uU9OxtygDkWRqLT9Q/X30V2XsUb6XUEPbSsdUiORfDPVQA==
|
||||
i18n-locales@^0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/i18n-locales/-/i18n-locales-0.0.4.tgz#95d6505f6563f870f68860c23d35f82bd805cbf5"
|
||||
integrity sha512-aP6VjhoBwSC8uZUehHWSszqdeWiheNXp0+oLPcZY4QAktsqcouHNYQee2NQFM4KNcCTKHHbfXrRUuOxjxF2jYw==
|
||||
dependencies:
|
||||
country-language "^0.1.7"
|
||||
|
||||
i18n@^0.8.4:
|
||||
version "0.8.4"
|
||||
|
@ -5642,10 +5631,10 @@ inquirer@^7.0.0:
|
|||
strip-ansi "^5.1.0"
|
||||
through "^2.3.6"
|
||||
|
||||
inquirer@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.3.tgz#f9b4cd2dff58b9f73e8d43759436ace15bed4567"
|
||||
integrity sha512-+OiOVeVydu4hnCGLCSX+wedovR/Yzskv9BFqUNNKq9uU2qg7LCcCo3R86S2E7WLo0y/x2pnEZfZe1CoYnORUAw==
|
||||
inquirer@^7.0.4:
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703"
|
||||
integrity sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==
|
||||
dependencies:
|
||||
ansi-escapes "^4.2.1"
|
||||
chalk "^2.4.2"
|
||||
|
@ -6138,7 +6127,7 @@ jsonfile@^4.0.0:
|
|||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
jsonwebtoken@^8.1.0, jsonwebtoken@^8.5.1:
|
||||
jsonwebtoken@^8.5.1:
|
||||
version "8.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d"
|
||||
integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==
|
||||
|
@ -6538,11 +6527,6 @@ lodash.reject@^4.4.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415"
|
||||
integrity sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=
|
||||
|
||||
lodash.set@^4.0.0:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
|
||||
integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=
|
||||
|
||||
lodash.snakecase@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d"
|
||||
|
@ -7044,10 +7028,10 @@ mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
|
|||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
modern-css-reset@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/modern-css-reset/-/modern-css-reset-1.0.4.tgz#4a1fff644cd0b314b048db23e16bccb9b7411caf"
|
||||
integrity sha512-HspLib3vUdgdGNV9JcBrQXlqiWB/tGr9oMaSiqGR7+J1kQmJbxlZzp/3ufDR3lZLwDlWDuMh2VtvSY+Aa0xNow==
|
||||
mkdirp@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.3.tgz#4cf2e30ad45959dddea53ad97d518b6c8205e1ea"
|
||||
integrity sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==
|
||||
|
||||
moment-timezone@^0.5.21:
|
||||
version "0.5.26"
|
||||
|
|
Loading…
Reference in a new issue