DB API Reads
This commit is contained in:
parent
fc5fc14b3f
commit
dfcaf046c6
121
app/controllers/api/v1/DatabaseAPI.controller.js
Normal file
121
app/controllers/api/v1/DatabaseAPI.controller.js
Normal file
@ -0,0 +1,121 @@
|
||||
const Controller = require('libflitter/controller/Controller')
|
||||
|
||||
/*
|
||||
* DatabaseAPI Controller
|
||||
* -------------------------------------------------------------
|
||||
* Put some description here!
|
||||
*/
|
||||
class DatabaseAPI extends Controller {
|
||||
static get services() {
|
||||
return [...super.services, 'models', 'utility']
|
||||
}
|
||||
|
||||
async databases(req, res, next) {
|
||||
const Database = this.models.get('api:db:Database')
|
||||
const dbs = await Database.visible_by_user(req.user)
|
||||
return res.api(dbs.map(x => x.to_api_object()))
|
||||
}
|
||||
|
||||
async get_database(req, res, next) {
|
||||
return res.api(req.form.database.to_api_object())
|
||||
}
|
||||
|
||||
async get_columns(req, res, next) {
|
||||
const db = req.form.database
|
||||
const cols = (await db.get_columns()).map(x => x.to_api_object())
|
||||
return res.api(cols)
|
||||
}
|
||||
|
||||
async get_columns_order(req, res, next) {
|
||||
return res.api(req.form.database.ColumnIds)
|
||||
}
|
||||
|
||||
async get_data(req, res, next) {
|
||||
const DBEntry = this.models.get('api:db:DBEntry')
|
||||
const db = req.form.database
|
||||
const cursor = await DBEntry.cursor({DatabaseId: db.UUID})
|
||||
|
||||
if ( req.query.sort ) {
|
||||
if ( this.utility.is_json(req.query.sort) ) {
|
||||
const sort = JSON.parse(req.query.sort)
|
||||
if ( typeof sort !== 'object' ) return res.status(400).message('Invalid sort field. Should be JSON object.').api()
|
||||
const sort_obj = {}
|
||||
for ( const field in sort ) {
|
||||
if ( !sort.hasOwnProperty(field) ) continue
|
||||
sort_obj[`RowData.${field}`] = (Number(sort[field]) < 0 ? -1 : 1)
|
||||
}
|
||||
cursor.sort(sort_obj)
|
||||
} else if ( req.query.sort ) {
|
||||
const sort_obj = {}
|
||||
sort_obj[`RowData.${req.query.sort}`] = (req.query.reverse ? -1 : 1)
|
||||
cursor.sort(sort_obj)
|
||||
}
|
||||
}
|
||||
|
||||
if ( req.query.limit ) {
|
||||
const limit = Number(req.query.limit)
|
||||
if ( !isNaN(limit) ) cursor.limit(limit)
|
||||
}
|
||||
|
||||
if ( req.query.skip ) {
|
||||
const skip = Number(req.query.skip)
|
||||
if ( !isNaN(skip) ) cursor.skip(skip)
|
||||
}
|
||||
|
||||
if ( req.query.where ) {
|
||||
if ( !this.utility.is_json(req.query.where) ) {
|
||||
return res.status(400).message('Invalid where field. Should be JSON object.').api()
|
||||
}
|
||||
|
||||
const wheres = JSON.parse(req.query.where)
|
||||
|
||||
if ( typeof wheres !== 'object' ) {
|
||||
return res.status(400).message('Invalid where field. Should be JSON object.').api()
|
||||
}
|
||||
|
||||
const wheres_object = {}
|
||||
for ( const field in wheres ) {
|
||||
if ( !wheres.hasOwnProperty(field) ) continue
|
||||
const value = wheres[field]
|
||||
if ( typeof value !== 'object' ) {
|
||||
wheres_object[`RowData.${field}`] = value
|
||||
} else {
|
||||
const sub_where = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data = (await DBEntry.from_cursor(cursor)).map(x => {
|
||||
x = x.to_api_object()
|
||||
if ( req.query.flatten ) {
|
||||
x = {
|
||||
uuid: x.uuid,
|
||||
database_id: x.database_id,
|
||||
...x.data,
|
||||
}
|
||||
}
|
||||
return x
|
||||
})
|
||||
return res.api(data)
|
||||
}
|
||||
|
||||
async get_record(req, res, next) {
|
||||
const DBEntry = this.models.get('api:db:DBEntry')
|
||||
const db = req.form.database
|
||||
const record = await DBEntry.findOne({UUID: req.params.record_id, DatabaseId: db.UUID})
|
||||
if ( record ) {
|
||||
const api_obj = record.to_api_object()
|
||||
if ( req.query.flatten ) {
|
||||
return res.api({
|
||||
uuid: api_obj.uuid,
|
||||
database_id: api_obj.database_id,
|
||||
...api_obj.data,
|
||||
})
|
||||
}
|
||||
return res.api(api_obj)
|
||||
}
|
||||
else return res.status(404).message('Database record not found with that ID.').api()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = DatabaseAPI
|
@ -8,12 +8,18 @@ const Page = require("../../../models/api/Page.model")
|
||||
* Put some description here!
|
||||
*/
|
||||
class Misc extends Controller {
|
||||
#default_token_grants = ['database']
|
||||
|
||||
hello_world(req, res) {
|
||||
return res.api({
|
||||
hello: 'world',
|
||||
})
|
||||
static get services() {
|
||||
return [...super.services, 'models']
|
||||
}
|
||||
|
||||
async get_token(req, res, next) {
|
||||
const Token = this.models.get('api:Token')
|
||||
const token = await Token.for_user(req.user)
|
||||
return res.api(token.token)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = exports = Misc
|
||||
|
@ -7,6 +7,10 @@ const uuid = require('uuid/v4');
|
||||
* Put some description here!
|
||||
*/
|
||||
class Node extends Model {
|
||||
static get services() {
|
||||
return [...super.services, 'models']
|
||||
}
|
||||
|
||||
static get schema() {
|
||||
// Return a flitter-orm schema here.
|
||||
return {
|
||||
@ -26,7 +30,7 @@ class Node extends Model {
|
||||
|
||||
// Static and instance methods can go here
|
||||
get page() {
|
||||
const Page = this.model.get("api:Page")
|
||||
const Page = this.models.get('api:Page')
|
||||
return this.belongs_to_one(Page, "PageId", "_id")
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,64 @@ class Page extends Model {
|
||||
|
||||
static scopes = [new ActiveScope]
|
||||
|
||||
static async visible_by_user(user) {
|
||||
const user_root = await user.get_root_page()
|
||||
const user_root_children = await user_root.visible_flat_children(user)
|
||||
|
||||
const view_only_trees = await this.find({ shared_users_view: user._id })
|
||||
let view_only_children = []
|
||||
for ( const tree of view_only_trees ) {
|
||||
if ( await tree.is_accessible_by(user) ) {
|
||||
view_only_children.push(tree)
|
||||
view_only_children = [...view_only_children, await tree.visible_flat_children(user)]
|
||||
}
|
||||
}
|
||||
|
||||
const update_trees = await this.find({ shared_users_update: user._id })
|
||||
let update_children = []
|
||||
for ( const tree of update_trees ) {
|
||||
if ( await tree.is_accessible_by(user) ) {
|
||||
update_children.push(tree)
|
||||
update_children = [...update_children, await tree.visible_flat_children(user)]
|
||||
}
|
||||
}
|
||||
|
||||
const manage_trees = await this.find({ shared_users_manage: user._id })
|
||||
let manage_children = []
|
||||
for ( const tree of manage_trees ) {
|
||||
if ( await tree.is_accessible_by(user) ) {
|
||||
manage_children.push(tree)
|
||||
manage_children = [...manage_children, await tree.visible_flat_children(user)]
|
||||
}
|
||||
}
|
||||
|
||||
const all_children = [...user_root_children, ...view_only_children, ...update_children, ...manage_children]
|
||||
const unique_children = []
|
||||
const seen_UUIDs = []
|
||||
all_children.forEach(child => {
|
||||
if ( !seen_UUIDs.includes(child.UUID) ) {
|
||||
unique_children.push(child)
|
||||
seen_UUIDs.push(child.UUID)
|
||||
}
|
||||
})
|
||||
|
||||
return unique_children
|
||||
}
|
||||
|
||||
async visible_flat_children(user) {
|
||||
const children = await this.childPages
|
||||
let visible = []
|
||||
if ( children ) {
|
||||
for ( const child of children ) {
|
||||
if ( !(await child.is_accessible_by(user)) ) continue
|
||||
visible.push(child)
|
||||
visible = [...visible, ...(await child.visible_flat_children(user))]
|
||||
}
|
||||
}
|
||||
|
||||
return visible
|
||||
}
|
||||
|
||||
is_shared() {
|
||||
return this.shared_users_view.length > 0 || this.shared_users_update.length > 0 || this.shared_users_manage.length > 0
|
||||
}
|
||||
|
95
app/models/api/Token.model.js
Normal file
95
app/models/api/Token.model.js
Normal file
@ -0,0 +1,95 @@
|
||||
const Model = require('flitter-orm/src/model/Model')
|
||||
const { ObjectId } = require('mongodb')
|
||||
const User = require('../auth/User.model')
|
||||
const ValidScope = require('../scopes/Valid.scope')
|
||||
const uuid = require('uuid/v4')
|
||||
const jwt = require('jsonwebtoken')
|
||||
|
||||
/*
|
||||
* Token Model
|
||||
* -------------------------------------------------------------
|
||||
* Put some description here!
|
||||
*/
|
||||
class Token extends Model {
|
||||
static #default_grants = ['database']
|
||||
|
||||
static get services() {
|
||||
return [...super.services, 'configs']
|
||||
}
|
||||
|
||||
static get schema() {
|
||||
// Return a flitter-orm schema here.
|
||||
return {
|
||||
user_id: ObjectId,
|
||||
token: String,
|
||||
issued: { type: Date, default: () => new Date },
|
||||
expires: {
|
||||
type: Date,
|
||||
default: () => {
|
||||
const d = new Date
|
||||
d.setDate(d.getDate() + 7)
|
||||
return d
|
||||
},
|
||||
},
|
||||
valid: { type: Boolean, default: true },
|
||||
grants: [String],
|
||||
}
|
||||
}
|
||||
|
||||
static scopes = [new ValidScope]
|
||||
|
||||
static async create(user) {
|
||||
const token = new this({ user_id: user._id, grants: this.#default_grants })
|
||||
await token.save()
|
||||
token.token = token.generate()
|
||||
return await token.save()
|
||||
}
|
||||
|
||||
static async for_user(user) {
|
||||
const token = await this.findOne({ user_id: user._id })
|
||||
return token ? token : await this.create(user)
|
||||
}
|
||||
|
||||
static verify(token) {
|
||||
const secret = this.prototype.configs.get('server.session.secret')
|
||||
const server = this.prototype.configs.get('app.url')
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
jwt.verify(token, secret, (err, decoded) => {
|
||||
if ( err ) rej(err)
|
||||
else if ( decoded.iss !== server ) rej(new Error('Invalid token issuer: '+decoded.iss))
|
||||
else {
|
||||
this.findOne({ user_id: ObjectId(decoded.sub) }).then(result => {
|
||||
if ( !result ) rej(new Error('Unable to find associated token. It may have been manually invalidated.'))
|
||||
else res(result)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
generate() {
|
||||
const secret = this.configs.get('server.session.secret')
|
||||
const server = this.configs.get('app.url')
|
||||
|
||||
const payload = {
|
||||
sub: String(this.user_id),
|
||||
iss: server,
|
||||
permissions: this.grants.join(','),
|
||||
exp: (this.expires.getTime()/1000 | 0),
|
||||
iat: (this.issued.getTime()/1000 | 0),
|
||||
}
|
||||
|
||||
return jwt.sign(payload, secret)
|
||||
}
|
||||
|
||||
user() {
|
||||
return this.has_one(User, 'user_id', '_id')
|
||||
}
|
||||
|
||||
can(grant) {
|
||||
return this.grants.includes(grant)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = Token
|
@ -33,6 +33,16 @@ class ColumnDef extends Model {
|
||||
data() {
|
||||
return JSON.parse(this.additionalData ? this.additionalData : '{}')
|
||||
}
|
||||
|
||||
to_api_object() {
|
||||
return {
|
||||
name: this.headerName,
|
||||
uuid: this.UUID,
|
||||
database_id: this.DatabaseId,
|
||||
type: this.Type,
|
||||
metadata: this.data()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = ColumnDef
|
||||
|
@ -17,6 +17,22 @@ class DBEntry extends Model {
|
||||
}
|
||||
|
||||
// Static and instance methods can go here
|
||||
to_api_object() {
|
||||
return {
|
||||
uuid: this.UUID,
|
||||
database_id: this.DatabaseId,
|
||||
data: this.RowData,
|
||||
}
|
||||
}
|
||||
|
||||
static async from_cursor(cursor) {
|
||||
const arr = await cursor.toArray()
|
||||
const collection = []
|
||||
for ( const rec of arr ) {
|
||||
collection.push(new this(rec))
|
||||
}
|
||||
return collection
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = DBEntry
|
||||
|
@ -1,6 +1,9 @@
|
||||
const Model = require('flitter-orm/src/model/Model')
|
||||
const uuid = require('uuid/v4')
|
||||
const ColumnDef = require('./ColumnDef.model')
|
||||
const Page = require('../Page.model')
|
||||
const Node = require('../Node.model')
|
||||
const ActiveScope = require('../../scopes/Active.scope')
|
||||
|
||||
/*
|
||||
* Database Model
|
||||
@ -16,18 +19,50 @@ class Database extends Model {
|
||||
PageId: String,
|
||||
ColumnIds: [String],
|
||||
UUID: { type: String, default: () => uuid() },
|
||||
Active: { type: Boolean, default: true },
|
||||
}
|
||||
}
|
||||
|
||||
accessible_by(user, mode = 'view') {
|
||||
return user.can(`database:${this.UUID}:${mode}`)
|
||||
static scopes = [new ActiveScope]
|
||||
|
||||
static async visible_by_user(user) {
|
||||
const page_ids = (await Page.visible_by_user(user)).map(x => x.UUID)
|
||||
return this.find({PageId: {$in: page_ids}})
|
||||
}
|
||||
|
||||
async is_accessible_by(user, mode = 'view') {
|
||||
const page = await this.page
|
||||
return page.is_accessible_by(user, mode)
|
||||
}
|
||||
|
||||
async get_columns() {
|
||||
return ColumnDef.find({DatabaseId: this.UUID});
|
||||
const cols = await ColumnDef.find({DatabaseId: this.UUID})
|
||||
const assoc_cols = {}
|
||||
cols.forEach(col => assoc_cols[col.UUID] = col)
|
||||
return this.ColumnIds.map(x => assoc_cols[x])
|
||||
}
|
||||
|
||||
get page() {
|
||||
return this.belongs_to_one(Page, 'PageId', 'UUID')
|
||||
}
|
||||
|
||||
get node() {
|
||||
return this.belongs_to_one(Node, 'NodeId', 'UUID')
|
||||
}
|
||||
|
||||
async delete() {
|
||||
this.Active = false
|
||||
await this.save()
|
||||
}
|
||||
|
||||
to_api_object() {
|
||||
return {
|
||||
name: this.Name,
|
||||
uuid: this.UUID,
|
||||
page_id: this.PageId,
|
||||
column_ids: this.ColumnIds,
|
||||
}
|
||||
}
|
||||
|
||||
// Static and instance methods can go here
|
||||
}
|
||||
|
||||
module.exports = exports = Database
|
||||
|
11
app/models/scopes/Valid.scope.js
Normal file
11
app/models/scopes/Valid.scope.js
Normal file
@ -0,0 +1,11 @@
|
||||
const Scope = require('flitter-orm/src/model/Scope')
|
||||
|
||||
class ValidScope extends Scope {
|
||||
async filter(to_filter) {
|
||||
return to_filter.equal('valid', true)
|
||||
.greater_than('expires', new Date)
|
||||
.less_than('issued', new Date)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = ValidScope
|
30
app/routing/middleware/api/DatabaseRoute.middleware.js
Normal file
30
app/routing/middleware/api/DatabaseRoute.middleware.js
Normal file
@ -0,0 +1,30 @@
|
||||
const Middleware = require('libflitter/middleware/Middleware')
|
||||
|
||||
/*
|
||||
* DatabaseRoute Middleware
|
||||
* -------------------------------------------------------------
|
||||
* Put some description here!
|
||||
*/
|
||||
class DatabaseRoute extends Middleware {
|
||||
static get services() {
|
||||
return [...super.services, 'models']
|
||||
}
|
||||
|
||||
async test(req, res, next, args = {}){
|
||||
const Database = this.models.get('api:db:Database')
|
||||
|
||||
const id = req.params.database_id ? req.params.database_id : (req.query.database_id ? req.query.database_id : false)
|
||||
if ( !id ) return res.status(400).message('Missing required: database_id').api()
|
||||
|
||||
const db = await Database.findOne({UUID: id})
|
||||
if ( !db ) return res.status(404).message('Unable to find database with that ID.').api()
|
||||
if ( !(await db.is_accessible_by(req.user)) ) return req.security.deny()
|
||||
|
||||
if ( !req.form ) req.form = {}
|
||||
req.form.database = db
|
||||
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = DatabaseRoute
|
52
app/routing/middleware/api/auth/BearerToken.middleware.js
Normal file
52
app/routing/middleware/api/auth/BearerToken.middleware.js
Normal file
@ -0,0 +1,52 @@
|
||||
const Middleware = require('libflitter/middleware/Middleware')
|
||||
|
||||
/*
|
||||
* BearerToken Middleware
|
||||
* -------------------------------------------------------------
|
||||
* Put some description here!
|
||||
*/
|
||||
class BearerToken extends Middleware {
|
||||
static get services() {
|
||||
return [...super.services, 'models']
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the middleware test.
|
||||
* This method is required by all Flitter middleware.
|
||||
* It should either call the next function in the stack,
|
||||
* or it should handle the response accordingly.
|
||||
*/
|
||||
async test(req, res, next, args = []){
|
||||
const Token = this.models.get('api:Token')
|
||||
|
||||
const token_string = req.headers.authorization
|
||||
if ( !token_string ) return this.fail(res, )
|
||||
else if ( !token_string.startsWith('bearer ') ) return this.fail(res, 'Invalid authorization token. Prefix with "bearer".')
|
||||
|
||||
try {
|
||||
const token = await Token.verify(token_string.replace('bearer ', ''))
|
||||
const user = await token.user()
|
||||
if ( !user || !token ) return this.fail(res)
|
||||
|
||||
if ( Array.isArray(args) ) {
|
||||
for (const grant of args) {
|
||||
if (!token.can(grant)) {
|
||||
return this.fail(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
req.user = user
|
||||
req.token = token
|
||||
next()
|
||||
} catch (e) {
|
||||
return this.fail(res, String(e))
|
||||
}
|
||||
}
|
||||
|
||||
fail(res, msg = 'Unauthorized') {
|
||||
return res.status(401).message(msg).api({})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = BearerToken
|
@ -12,6 +12,10 @@ const index = {
|
||||
],
|
||||
|
||||
get: {
|
||||
'/token': [
|
||||
'controller::api:v1:Misc.get_token',
|
||||
],
|
||||
|
||||
// Get the file ref node config for the specified file ref
|
||||
'/files/:PageId/:NodeId/get/:FilesId': ['controller::api:v1:File.get_config'],
|
||||
|
||||
|
43
app/routing/routers/api/v1/database.routes.js
Normal file
43
app/routing/routers/api/v1/database.routes.js
Normal file
@ -0,0 +1,43 @@
|
||||
module.exports = exports = {
|
||||
|
||||
prefix: '/db_api/v1',
|
||||
|
||||
middleware: [
|
||||
// JWT authorization middleware. Sets req.user and req.token.
|
||||
// Second param is array of required grants.
|
||||
['api:auth:BearerToken', ['database']],
|
||||
],
|
||||
|
||||
get: {
|
||||
'/': [ 'controller::api:v1:DatabaseAPI.databases' ],
|
||||
|
||||
'/:database_id': [
|
||||
'middleware::api:DatabaseRoute',
|
||||
'controller::api:v1:DatabaseAPI.get_database',
|
||||
],
|
||||
|
||||
'/:database_id/columns': [
|
||||
'middleware::api:DatabaseRoute',
|
||||
'controller::api:v1:DatabaseAPI.get_columns',
|
||||
],
|
||||
|
||||
'/:database_id/columns/order': [
|
||||
'middleware::api:DatabaseRoute',
|
||||
'controller::api:v1:DatabaseAPI.get_columns_order',
|
||||
],
|
||||
|
||||
'/:database_id/data': [
|
||||
'middleware::api:DatabaseRoute',
|
||||
'controller::api:v1:DatabaseAPI.get_data',
|
||||
],
|
||||
|
||||
'/:database_id/record/:record_id': [
|
||||
'middleware::api:DatabaseRoute',
|
||||
'controller::api:v1:DatabaseAPI.get_record',
|
||||
],
|
||||
},
|
||||
|
||||
post: {
|
||||
|
||||
},
|
||||
}
|
@ -16,7 +16,8 @@ const auth_config = {
|
||||
|
||||
// Get the token user's data
|
||||
user: {
|
||||
enable: env('OAUTH2_SERVER_ENABLE', true),
|
||||
// enable: env('OAUTH2_SERVER_ENABLE', true),
|
||||
enable: false,
|
||||
|
||||
// Fields to return to the endpoint
|
||||
// The keys are the keys in the request. The values are the keys in the user.
|
||||
|
@ -21,4 +21,4 @@ AUTH_FLITTER_ENABLE=true
|
||||
|
||||
#insert client ID for oauth
|
||||
AUTH_OAUTH2_CLIENT_ID=
|
||||
AUTH_OAUTH2_CLIENT_SECRET=
|
||||
AUTH_OAUTH2_CLIENT_SECRET=
|
||||
|
@ -24,6 +24,7 @@
|
||||
"flitter-forms": "^0.8.1",
|
||||
"flitter-orm": "^0.2.4",
|
||||
"flitter-upload": "^0.8.0",
|
||||
"libflitter": "^0.46.7"
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"libflitter": "^0.46.8"
|
||||
}
|
||||
}
|
||||
|
90
yarn.lock
90
yarn.lock
@ -435,6 +435,11 @@ bson@^1.1.1, bson@~1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.1.tgz#4330f5e99104c4e751e7351859e2d408279f2f13"
|
||||
integrity sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg==
|
||||
|
||||
buffer-equal-constant-time@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
|
||||
integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=
|
||||
|
||||
bunyan@1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.3.3.tgz#bf4e301c1f0bf888ec678829531f7b5d212e9e81"
|
||||
@ -798,6 +803,13 @@ dtrace-provider@0.4.0, dtrace-provider@~0.4:
|
||||
dependencies:
|
||||
nan "~1.5.1"
|
||||
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
|
||||
integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
editorconfig@^0.15.3:
|
||||
version "0.15.3"
|
||||
resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5"
|
||||
@ -1436,6 +1448,22 @@ jsonfile@^2.1.0:
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
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==
|
||||
dependencies:
|
||||
jws "^3.2.2"
|
||||
lodash.includes "^4.3.0"
|
||||
lodash.isboolean "^3.0.3"
|
||||
lodash.isinteger "^4.0.4"
|
||||
lodash.isnumber "^3.0.3"
|
||||
lodash.isplainobject "^4.0.6"
|
||||
lodash.isstring "^4.0.1"
|
||||
lodash.once "^4.0.0"
|
||||
ms "^2.1.1"
|
||||
semver "^5.6.0"
|
||||
|
||||
jstransformer@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3"
|
||||
@ -1444,6 +1472,23 @@ jstransformer@1.0.0:
|
||||
is-promise "^2.0.0"
|
||||
promise "^7.0.1"
|
||||
|
||||
jwa@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
|
||||
integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==
|
||||
dependencies:
|
||||
buffer-equal-constant-time "1.0.1"
|
||||
ecdsa-sig-formatter "1.0.11"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
jws@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
|
||||
integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
|
||||
dependencies:
|
||||
jwa "^1.4.1"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
kareem@2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.0.tgz#ef33c42e9024dce511eeaf440cd684f3af1fc769"
|
||||
@ -1509,10 +1554,10 @@ leven@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3"
|
||||
integrity sha1-kUS27ryl8dBoAWnxpncNzqYLdcM=
|
||||
|
||||
libflitter@^0.46.7:
|
||||
version "0.46.7"
|
||||
resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.46.7.tgz#be55386a53747e1e21b2aefd356977900fd40dd1"
|
||||
integrity sha512-PPPEp4vR36xAvjPyxmU8K6NBv6n5ggP/bfSJU/PZ6qCChbYh0gKIN6kH88GM38imSZJxjZM1hjvzio5veIGaAw==
|
||||
libflitter@^0.46.8:
|
||||
version "0.46.8"
|
||||
resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.46.8.tgz#1500d70956628ff1db9719ff4086a8b0b313aa6e"
|
||||
integrity sha512-ZAo4iUeTLz+6crqQG9UUJyliT6L7+kuZyTB39q8FC8qIdwtLd6C28Jkx82sBcYp9JZ5qJsbNYjSlF42Yt/msbg==
|
||||
dependencies:
|
||||
colors "^1.3.3"
|
||||
connect-mongodb-session "^2.2.0"
|
||||
@ -1554,6 +1599,41 @@ lodash.clonedeep@4.x:
|
||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
|
||||
|
||||
lodash.includes@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
|
||||
integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=
|
||||
|
||||
lodash.isboolean@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
|
||||
integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=
|
||||
|
||||
lodash.isinteger@^4.0.4:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
|
||||
integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=
|
||||
|
||||
lodash.isnumber@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
|
||||
integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=
|
||||
|
||||
lodash.isplainobject@^4.0.6:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
|
||||
integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
|
||||
|
||||
lodash.isstring@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
|
||||
integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=
|
||||
|
||||
lodash.once@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
|
||||
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
|
||||
|
||||
lodash.set@4.x:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
|
||||
@ -2508,7 +2588,7 @@ safe-buffer@5.1.2, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
safe-buffer@^5.1.1:
|
||||
safe-buffer@^5.0.1, safe-buffer@^5.1.1:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
|
||||
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
|
||||
|
Loading…
Reference in New Issue
Block a user