From 66ba4e687f90dc519b2f4c8dc91f3574caaa288f Mon Sep 17 00:00:00 2001 From: michael shanks Date: Fri, 28 Jun 2019 22:59:27 +0100 Subject: [PATCH] creating new apps ... --- .gitignore | 1 + packages/core | 2 +- packages/datastores/datastores/local.js | 7 + packages/server/app.js | 8 +- .../appPackages/master/appDefinition.json | 424 +----------------- packages/server/appPackages/master/main.js | 60 +++ packages/server/appPackages/master/plugins.js | 4 + .../server/appPackages/master/plugins.json | 1 - .../appPackages/testApp/access_levels.json | 1 + .../appPackages/testApp/appDefinition.json | 1 + .../appPackages/testApp/dist/package.tar.gz | Bin 0 -> 1500 bytes packages/server/config.js | 2 +- packages/server/config.sample.js | 4 +- .../server/initialise/createInstanceDb.js | 42 ++ packages/server/initialise/createMasterDb.js | 21 +- .../server/initialise/initialiseBudibase.js | 10 +- .../initialise/initialiseRuntimePackages.js | 26 +- packages/server/middleware/routers.js | 28 +- packages/server/package.json | 6 +- packages/server/tests/all.spec.js | 2 + packages/server/tests/authenticate.js | 52 ++- packages/server/tests/createNewApp.js | 72 +++ packages/server/tests/helpers.js | 9 + packages/server/tests/testApp.js | 25 +- .../server/utilities/constructHierarchy.js | 6 + packages/server/utilities/createAppPackage.js | 29 +- packages/server/utilities/fsawait.js | 19 + packages/server/utilities/runtimePackages.js | 8 + packages/server/utilities/statusCodes.js | 3 +- packages/server/utilities/targzAppPackage.js | 91 ++++ packages/server/yarn.lock | 156 +++++-- 31 files changed, 568 insertions(+), 552 deletions(-) create mode 100644 packages/server/appPackages/master/main.js create mode 100644 packages/server/appPackages/master/plugins.js delete mode 100644 packages/server/appPackages/master/plugins.json create mode 100644 packages/server/appPackages/testApp/access_levels.json create mode 100644 packages/server/appPackages/testApp/appDefinition.json create mode 100644 packages/server/appPackages/testApp/dist/package.tar.gz create mode 100644 packages/server/initialise/createInstanceDb.js create mode 100644 packages/server/tests/createNewApp.js create mode 100644 packages/server/tests/helpers.js create mode 100644 packages/server/utilities/constructHierarchy.js create mode 100644 packages/server/utilities/fsawait.js create mode 100644 packages/server/utilities/runtimePackages.js create mode 100644 packages/server/utilities/targzAppPackage.js diff --git a/.gitignore b/.gitignore index 48a49d382..4e653a647 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .data/ +.temp/ # Logs logs diff --git a/packages/core b/packages/core index feb2f3412..babcb77e7 160000 --- a/packages/core +++ b/packages/core @@ -1 +1 @@ -Subproject commit feb2f3412a0e3748d6509a3693b1f38c448bd743 +Subproject commit babcb77e70088ddd689062e1d02d8fe2c5bc3417 diff --git a/packages/datastores/datastores/local.js b/packages/datastores/datastores/local.js index 9dffc0348..aa7a4dad5 100644 --- a/packages/datastores/datastores/local.js +++ b/packages/datastores/datastores/local.js @@ -11,6 +11,7 @@ const rmdir = promisify(fs.rmdir); const unlink = promisify(fs.unlink); const readdir = promisify(fs.readdir); const rename = promisify(fs.rename); +const stat = promisify(fs.stat); const updateFile = root => async (path, file) => await writeFile( @@ -77,6 +78,11 @@ const renameFile = root => async (oldPath, newPath) => join(root, newPath) ); +const getFileSize = root => async (path) => + (await stat( + join(root,path) + )).size; + const datastoreFolder = (applicationId, instanceId) => applicationId === "master" ? "master" : `app.${applicationId}.${instanceId}`; @@ -120,6 +126,7 @@ module.exports.getDatastore = rootFolderPath => ({ writableFileStream: writableFileStream(rootFolderPath), renameFile: renameFile(rootFolderPath), getFolderContents: getFolderContents(rootFolderPath), + getFileSize: getFileSize(rootFolderPath), createEmptyDb: createEmptyDb(rootFolderPath), datastoreType : "local", datastoreDescription: rootFolderPath diff --git a/packages/server/app.js b/packages/server/app.js index 6afae2930..7f95aea91 100644 --- a/packages/server/app.js +++ b/packages/server/app.js @@ -2,19 +2,19 @@ const Koa = require('koa'); const app = new Koa(); const getMasterAppInternal = require("./utilities/masterAppInternal"); const router = require("./middleware/routers"); -const bodyParser = require('koa-bodyparser'); -const initialiseRuntimeApps = require("./initialise/initialiseRuntimePackages"); +const koaBody = require('koa-body'); +const initialiseRuntimePackages = require("./initialise/initialiseRuntimePackages"); module.exports = async (config) => { app.keys = config.keys; app.context.master = await getMasterAppInternal(config); - app.context.getAppPackage = await initialiseRuntimeApps( + app.context.getAppPackage = await initialiseRuntimePackages( config, app.context.master, config.latestAppsPath ) - app.use(bodyParser()); + app.use(koaBody({ multipart : true })); app.use(router(config, app).routes()); return app.listen(); }; diff --git a/packages/server/appPackages/master/appDefinition.json b/packages/server/appPackages/master/appDefinition.json index 9534589ba..5cb778ac4 100644 --- a/packages/server/appPackages/master/appDefinition.json +++ b/packages/server/appPackages/master/appDefinition.json @@ -1,423 +1 @@ -{ - "hierarchy": { - "name": "root", - "type": "root", - "children": [ - { - "name": "application", - "type": "record", - "fields": [ - { - "name": "name", - "type": "string", - "typeOptions": { - "maxLength": 500, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "Name", - "getInitialValue": "default", - "getUndefinedValue": "default" - }, - { - "name": "domain", - "type": "string", - "typeOptions": { - "maxLength": 500, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "domain", - "getInitialValue": "default", - "getUndefinedValue": "default" - }, - { - "name": "application_resolve_strategy", - "type": "string", - "typeOptions": { - "maxLength": 100, - "values": [ - "domain", - "path" - ], - "allowDeclaredValuesOnly": true - }, - "label": "Resolve Application By", - "getInitialValue": "default", - "getUndefinedValue": "default" - } - ], - "children": [ - { - "name": "user", - "type": "record", - "fields": [ - { - "name": "unique_name", - "type": "string", - "typeOptions": { - "maxLength": 200, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "Name (unique)", - "getInitialValue": "default", - "getUndefinedValue": "default" - }, - { - "name": "active", - "type": "bool", - "typeOptions": { - "allowNulls": false - }, - "label": "Is Active", - "getInitialValue": "default", - "getUndefinedValue": "default" - }, - { - "name": "instance", - "type": "reference", - "typeOptions": { - "indexNodeKey": "/applications/1-{id}/allinstances", - "reverseIndexNodeKeys": [ - "/applications/1-{id}/instances/2-{id}/users_on_this_instance" - ], - "displayValue": "name" - }, - "label": "Instance", - "getInitialValue": "default", - "getUndefinedValue": "default" - } - ], - "children": [], - "validationRules": [], - "nodeId": 8, - "indexes": [], - "allidsShardFactor": "64", - "collectionName": "users", - "isSingle": false - }, - { - "name": "instance", - "type": "record", - "fields": [ - { - "name": "name", - "type": "string", - "typeOptions": { - "maxLength": 1000, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "Name", - "getInitialValue": "default", - "getUndefinedValue": "default" - }, - { - "name": "active", - "type": "bool", - "typeOptions": { - "allowNulls": false - }, - "label": "Is Active", - "getInitialValue": "default", - "getUndefinedValue": "default" - }, - { - "name": "version", - "type": "reference", - "typeOptions": { - "indexNodeKey": "/applications/1-{id}/all_versions", - "reverseIndexNodeKeys": [ - "/applications/1-{id}/versions/3-{id}/instances_on_this_version" - ], - "displayValue": "name" - }, - "label": "Version", - "getInitialValue": "default", - "getUndefinedValue": "default" - }, - { - "name": "datastoreconfig", - "type": "string", - "typeOptions": { - "maxLength": 1000, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "Datastore Config", - "getInitialValue": "default", - "getUndefinedValue": "default" - } - ], - "children": [], - "validationRules": [], - "nodeId": 2, - "indexes": [ - { - "name": "users_on_this_instance", - "type": "index", - "map": "return {...record};", - "filter": "", - "indexType": "reference", - "getShardName": "", - "getSortKey": "record.id", - "aggregateGroups": [], - "allowedRecordNodeIds": [], - "nodeId": 15 - } - ], - "allidsShardFactor": 1, - "collectionName": "instances", - "isSingle": false - }, - { - "name": "version", - "type": "record", - "fields": [ - { - "name": "name", - "type": "string", - "typeOptions": { - "maxLength": 200, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "Name", - "getInitialValue": "default", - "getUndefinedValue": "default" - } - ], - "children": [], - "validationRules": [], - "nodeId": 3, - "indexes": [ - { - "name": "instances_for_this_version", - "type": "index", - "map": "return {name:record.name};", - "filter": "", - "indexType": "ancestor", - "getShardName": "", - "getSortKey": "record.id", - "aggregateGroups": [], - "allowedRecordNodeIds": [], - "nodeId": 9 - }, - { - "name": "instances_on_this_version", - "type": "index", - "map": "return {...record};", - "filter": "", - "indexType": "reference", - "getShardName": "", - "getSortKey": "record.id", - "aggregateGroups": [], - "allowedRecordNodeIds": [], - "nodeId": 10 - } - ], - "allidsShardFactor": 1, - "collectionName": "versions", - "isSingle": false - }, - { - "name": "session", - "type": "record", - "fields": [ - { - "name": "created", - "type": "number", - "typeOptions": { - "minValue": 0, - "maxValue": 99999999999999, - "decimalPlaces": 0 - }, - "label": "Created", - "getInitialValue": "default", - "getUndefinedValue": "default" - }, - { - "name": "user_json", - "type": "string", - "typeOptions": { - "maxLength": null, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "User Json", - "getInitialValue": "default", - "getUndefinedValue": "default" - }, - { - "name": "instanceDatastoreConfig", - "type": "string", - "typeOptions": { - "maxLength": null, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "Instance Datastore Config", - "getInitialValue": "default", - "getUndefinedValue": "default" - }, - { - "name": "username", - "type": "string", - "typeOptions": { - "maxLength": null, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "User", - "getInitialValue": "default", - "getUndefinedValue": "default" - } - ], - "children": [], - "validationRules": [], - "nodeId": 16, - "indexes": [], - "allidsShardFactor": 1, - "collectionName": "sessions", - "isSingle": false - } - ], - "validationRules": [], - "nodeId": 1, - "indexes": [ - { - "name": "allinstances", - "type": "index", - "map": "return {...record};", - "filter": "", - "indexType": "ancestor", - "getShardName": "", - "getSortKey": "record.id", - "aggregateGroups": [], - "allowedRecordNodeIds": [ - 2 - ], - "nodeId": 23 - }, - { - "name": "sessions_by_user", - "type": "index", - "map": "return {username:record.username};", - "filter": "", - "indexType": "ancestor", - "getShardName": "return record.username.substring(0,2)", - "getSortKey": "record.id", - "aggregateGroups": [], - "allowedRecordNodeIds": [ - 16 - ], - "nodeId": 24 - }, - { - "name": "user_name_lookup", - "type": "index", - "map": "return {name:record.name, instanceDatastoreConfig:instance.datastoreconfig};", - "filter": "", - "indexType": "ancestor", - "getShardName": "return record.name.substring(0,2)", - "getSortKey": "record.id", - "aggregateGroups": [], - "allowedRecordNodeIds": [ - 8 - ], - "nodeId": 25 - }, - { - "name": "all_versions", - "type": "index", - "map": "return {...record};", - "filter": "", - "indexType": "ancestor", - "getShardName": "", - "getSortKey": "record.id", - "aggregateGroups": [], - "allowedRecordNodeIds": [ - 3 - ], - "nodeId": 26 - } - ], - "allidsShardFactor": 64, - "collectionName": "applications", - "isSingle": false - }, - { - "name": "mastersession", - "type": "record", - "fields": [ - { - "name": "user_json", - "type": "string", - "typeOptions": { - "maxLength": 10000, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "User Json", - "getInitialValue": "default", - "getUndefinedValue": "default" - }, - { - "name": "username", - "type": "string", - "typeOptions": { - "maxLength": null, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "User", - "getInitialValue": "default", - "getUndefinedValue": "default" - } - ], - "children": [], - "validationRules": [], - "nodeId": 17, - "indexes": [], - "allidsShardFactor": 64, - "collectionName": "sessions", - "isSingle": false - } - ], - "pathMaps": [], - "indexes": [ - { - "name": "all_applications", - "type": "index", - "map": "return {...record};", - "filter": "", - "indexType": "ancestor", - "getShardName": "", - "getSortKey": "record.id", - "aggregateGroups": [], - "allowedRecordNodeIds": [ - 1 - ], - "nodeId": 22 - }, - { - "name": "mastersessions_by_user", - "type": "index", - "map": "return {username:record.username};", - "filter": "", - "indexType": "ancestor", - "getShardName": "return record.username.substring(0,2)", - "getSortKey": "record.id", - "aggregateGroups": [], - "allowedRecordNodeIds": [ - 17 - ], - "nodeId": 27 - } - ], - "nodeId": 0 - }, - "actions": {}, - "triggers": [] -} \ No newline at end of file +{"hierarchy":{"name":"root","type":"root","children":[{"name":"application","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":500,"values":null,"allowDeclaredValuesOnly":false},"label":"Name","getInitialValue":"default","getUndefinedValue":"default"},{"name":"domain","type":"string","typeOptions":{"maxLength":500,"values":null,"allowDeclaredValuesOnly":false},"label":"domain","getInitialValue":"default","getUndefinedValue":"default"},{"name":"application_resolve_strategy","type":"string","typeOptions":{"maxLength":100,"values":["domain","path"],"allowDeclaredValuesOnly":true},"label":"Resolve Application By","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"user","type":"record","fields":[{"name":"unique_name","type":"string","typeOptions":{"maxLength":200,"values":null,"allowDeclaredValuesOnly":false},"label":"Name (unique)","getInitialValue":"default","getUndefinedValue":"default"},{"name":"active","type":"bool","typeOptions":{"allowNulls":false},"label":"Is Active","getInitialValue":"default","getUndefinedValue":"default"},{"name":"instance","type":"reference","typeOptions":{"indexNodeKey":"/applications/1-{id}/allinstances","reverseIndexNodeKeys":["/applications/1-{id}/instances/2-{id}/users_on_this_instance"],"displayValue":"name"},"label":"Instance","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":8,"indexes":[],"allidsShardFactor":"64","collectionName":"users","isSingle":false},{"name":"instance","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"Name","getInitialValue":"default","getUndefinedValue":"default"},{"name":"active","type":"bool","typeOptions":{"allowNulls":false},"label":"Is Active","getInitialValue":"default","getUndefinedValue":"default"},{"name":"version","type":"reference","typeOptions":{"indexNodeKey":"/applications/1-{id}/all_versions","reverseIndexNodeKeys":["/applications/1-{id}/versions/3-{id}/instances_on_this_version"],"displayValue":"name"},"label":"Version","getInitialValue":"default","getUndefinedValue":"default"},{"name":"datastoreconfig","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"Datastore Config","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[{"name":"users_on_this_instance","type":"index","map":"return {...record};","filter":"","indexType":"reference","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[],"nodeId":15}],"allidsShardFactor":1,"collectionName":"instances","isSingle":false},{"name":"version","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":200,"values":null,"allowDeclaredValuesOnly":false},"label":"Name","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":3,"indexes":[{"name":"instances_for_this_version","type":"index","map":"return {name:record.name};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[],"nodeId":9},{"name":"instances_on_this_version","type":"index","map":"return {...record};","filter":"","indexType":"reference","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[],"nodeId":10}],"allidsShardFactor":1,"collectionName":"versions","isSingle":false},{"name":"session","type":"record","fields":[{"name":"created","type":"number","typeOptions":{"minValue":0,"maxValue":99999999999999,"decimalPlaces":0},"label":"Created","getInitialValue":"default","getUndefinedValue":"default"},{"name":"user_json","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"User Json","getInitialValue":"default","getUndefinedValue":"default"},{"name":"instanceDatastoreConfig","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"Instance Datastore Config","getInitialValue":"default","getUndefinedValue":"default"},{"name":"username","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"User","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":16,"indexes":[],"allidsShardFactor":1,"collectionName":"sessions","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[{"name":"allinstances","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":23},{"name":"sessions_by_user","type":"index","map":"return {username:record.username};","filter":"","indexType":"ancestor","getShardName":"return record.username.substring(0,2)","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[16],"nodeId":24},{"name":"user_name_lookup","type":"index","map":"return {name:record.name, instanceDatastoreConfig:instance.datastoreconfig};","filter":"","indexType":"ancestor","getShardName":"return record.name.substring(0,2)","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[8],"nodeId":25},{"name":"all_versions","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[3],"nodeId":26}],"allidsShardFactor":64,"collectionName":"applications","isSingle":false},{"name":"mastersession","type":"record","fields":[{"name":"user_json","type":"string","typeOptions":{"maxLength":10000,"values":null,"allowDeclaredValuesOnly":false},"label":"User Json","getInitialValue":"default","getUndefinedValue":"default"},{"name":"username","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"User","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":17,"indexes":[],"allidsShardFactor":64,"collectionName":"sessions","isSingle":false}],"pathMaps":[],"indexes":[{"name":"all_applications","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[1],"nodeId":22},{"name":"mastersessions_by_user","type":"index","map":"return {username:record.username};","filter":"","indexType":"ancestor","getShardName":"return record.username.substring(0,2)","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[17],"nodeId":27}],"nodeId":0},"actions":{},"triggers":[]} \ No newline at end of file diff --git a/packages/server/appPackages/master/main.js b/packages/server/appPackages/master/main.js new file mode 100644 index 000000000..a5f106176 --- /dev/null +++ b/packages/server/appPackages/master/main.js @@ -0,0 +1,60 @@ +const { tmpdir } = require("os"); +const { join } = require("path"); +const uuid = require("uuid/v1"); +const { take, takeRight } = require("lodash/fp"); +const { splitKey, $ } = require("budibase-core").common; +const { unzipTarGzPackageToRuntime } = require("../../utilities/targzAppPackage"); +const { getRuntimePackageDirectory } = require("../../utilities/runtimePackages"); +const { exists } = require("../../utilities/fsawait"); +const createInstanceDb = require("../../initialise/createInstanceDb"); + +module.exports = (config) => ({ + initialiseInstance : async ({ instance, apis }) => { + + const appKey = $(instance.key, [ + splitKey, + take(2) + ]); + + const application = await apis.recordApi.load(appKey); + + const dbConfig = await createInstanceDb( + require(config.datastore), + config.datastoreConfig, + application.id, + instance.id + ); + + const versionId = $(instance.version.key, [ + splitKey, + takeRight(1) + ]); + + const runtimeDir = getRuntimePackageDirectory( + application.name, + versionId); + + if(!await exists(runtimeDir)) + await downloadAppPackage(instance, application.name, versionId); + + instance.datastoreconfig = JSON.stringify(dbConfig); + instance.isNew = false; + await apis.recordApi.save(instance); + } +}); + +const downloadAppPackage = async (instance, appName, versionId) => { + const inputStream = apis.recordApi.downloadFile(instance.key, "package.tar.gz"); + + const tempFilePath = join(tmpdir(), `bbpackage_${uuid()}.tar.gz`); + const outputStream = await app.datastore.writableFileStream( + tempFilePath); + + await new Promise((resolve,reject) => { + inputStream.pipe(outputStream); + outputStream.on('error', reject); + outputStream.on('finish', resolve); + }); + + await unzipTarGzPackageToRuntime(tempFilePath, appName, versionId); +} \ No newline at end of file diff --git a/packages/server/appPackages/master/plugins.js b/packages/server/appPackages/master/plugins.js new file mode 100644 index 000000000..5d3a4ddb9 --- /dev/null +++ b/packages/server/appPackages/master/plugins.js @@ -0,0 +1,4 @@ + +module.exports = config => ({ + main: require("./main")(config) +}); \ No newline at end of file diff --git a/packages/server/appPackages/master/plugins.json b/packages/server/appPackages/master/plugins.json deleted file mode 100644 index 9e26dfeeb..000000000 --- a/packages/server/appPackages/master/plugins.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/packages/server/appPackages/testApp/access_levels.json b/packages/server/appPackages/testApp/access_levels.json new file mode 100644 index 000000000..ebb7ca11a --- /dev/null +++ b/packages/server/appPackages/testApp/access_levels.json @@ -0,0 +1 @@ +{"levels":[{"name":"owner","permissions":[{"type":"create record","nodeKey":"/applications/1-{id}"},{"type":"update record","nodeKey":"/applications/1-{id}"},{"type":"delete record","nodeKey":"/applications/1-{id}"},{"type":"read record","nodeKey":"/applications/1-{id}"},{"type":"create record","nodeKey":"/applications/1-{id}/users/8-{id}"},{"type":"update record","nodeKey":"/applications/1-{id}/users/8-{id}"},{"type":"delete record","nodeKey":"/applications/1-{id}/users/8-{id}"},{"type":"read record","nodeKey":"/applications/1-{id}/users/8-{id}"},{"type":"create record","nodeKey":"/applications/1-{id}/instances/2-{id}"},{"type":"update record","nodeKey":"/applications/1-{id}/instances/2-{id}"},{"type":"delete record","nodeKey":"/applications/1-{id}/instances/2-{id}"},{"type":"read record","nodeKey":"/applications/1-{id}/instances/2-{id}"},{"type":"create record","nodeKey":"/applications/1-{id}/versions/3-{id}"},{"type":"update record","nodeKey":"/applications/1-{id}/versions/3-{id}"},{"type":"delete record","nodeKey":"/applications/1-{id}/versions/3-{id}"},{"type":"read record","nodeKey":"/applications/1-{id}/versions/3-{id}"},{"type":"create record","nodeKey":"/applications/1-{id}/sessions/16-{id}"},{"type":"update record","nodeKey":"/applications/1-{id}/sessions/16-{id}"},{"type":"delete record","nodeKey":"/applications/1-{id}/sessions/16-{id}"},{"type":"read record","nodeKey":"/applications/1-{id}/sessions/16-{id}"},{"type":"create record","nodeKey":"/sessions/17-{id}"},{"type":"update record","nodeKey":"/sessions/17-{id}"},{"type":"delete record","nodeKey":"/sessions/17-{id}"},{"type":"read record","nodeKey":"/sessions/17-{id}"},{"type":"read index","nodeKey":"/mastersessions_by_user"},{"type":"read index","nodeKey":"/all_applications"},{"type":"read index","nodeKey":"/applications/1-{id}/allinstances"},{"type":"read index","nodeKey":"/applications/1-{id}/sessions_by_user"},{"type":"read index","nodeKey":"/applications/1-{id}/user_name_lookup"},{"type":"read index","nodeKey":"/applications/1-{id}/all_versions"},{"type":"read index","nodeKey":"/applications/1-{id}/instances/2-{id}/users_on_this_instance"},{"type":"read index","nodeKey":"/applications/1-{id}/versions/3-{id}/instances_for_this_version"},{"type":"read index","nodeKey":"/applications/1-{id}/versions/3-{id}/instances_on_this_version"},{"type":"write templates"},{"type":"create user"},{"type":"set password"},{"type":"create temporary access"},{"type":"enable or disable user"},{"type":"write access levels"},{"type":"list users"},{"type":"list access levels"},{"type":"manage index"},{"type":"manage collection"},{"type":"set user access levels"}]}],"version":0} \ No newline at end of file diff --git a/packages/server/appPackages/testApp/appDefinition.json b/packages/server/appPackages/testApp/appDefinition.json new file mode 100644 index 000000000..61f0510f5 --- /dev/null +++ b/packages/server/appPackages/testApp/appDefinition.json @@ -0,0 +1 @@ +{"hierarchy":{"name":"root","type":"root","children":[{"name":"application","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":500,"values":null,"allowDeclaredValuesOnly":false},"label":"Name","getInitialValue":"default","getUndefinedValue":"default"},{"name":"domain","type":"string","typeOptions":{"maxLength":500,"values":null,"allowDeclaredValuesOnly":false},"label":"domain","getInitialValue":"default","getUndefinedValue":"default"},{"name":"application_resolve_strategy","type":"string","typeOptions":{"maxLength":100,"values":["domain","path"],"allowDeclaredValuesOnly":true},"label":"Resolve Application By","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"user","type":"record","fields":[{"name":"unique_name","type":"string","typeOptions":{"maxLength":200,"values":null,"allowDeclaredValuesOnly":false},"label":"Name (unique)","getInitialValue":"default","getUndefinedValue":"default"},{"name":"active","type":"bool","typeOptions":{"allowNulls":false},"label":"Is Active","getInitialValue":"default","getUndefinedValue":"default"},{"name":"instance","type":"reference","typeOptions":{"indexNodeKey":"/applications/1-{id}/allinstances","reverseIndexNodeKeys":["/applications/1-{id}/instances/2-{id}/users_on_this_instance"],"displayValue":"name"},"label":"Instance","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":8,"indexes":[],"allidsShardFactor":"64","collectionName":"users","isSingle":false},{"name":"instance","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"Name","getInitialValue":"default","getUndefinedValue":"default"},{"name":"active","type":"bool","typeOptions":{"allowNulls":false},"label":"Is Active","getInitialValue":"default","getUndefinedValue":"default"},{"name":"version","type":"reference","typeOptions":{"indexNodeKey":"/applications/1-{id}/all_versions","reverseIndexNodeKeys":["/applications/1-{id}/versions/3-{id}/instances_on_this_version"],"displayValue":"name"},"label":"Version","getInitialValue":"default","getUndefinedValue":"default"},{"name":"datastoreconfig","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"Datastore Config","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[{"name":"users_on_this_instance","type":"index","map":"return {...record};","filter":"","indexType":"reference","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[],"nodeId":15}],"allidsShardFactor":1,"collectionName":"instances","isSingle":false},{"name":"version","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":200,"values":null,"allowDeclaredValuesOnly":false},"label":"Name","getInitialValue":"default","getUndefinedValue":"default"},{"name":"package","type":"file","typeOptions":{},"label":"Package","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":3,"indexes":[{"name":"instances_for_this_version","type":"index","map":"return {name:record.name};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[],"nodeId":9},{"name":"instances_on_this_version","type":"index","map":"return {...record};","filter":"","indexType":"reference","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[],"nodeId":10}],"allidsShardFactor":1,"collectionName":"versions","isSingle":false},{"name":"session","type":"record","fields":[{"name":"created","type":"number","typeOptions":{"minValue":0,"maxValue":99999999999999,"decimalPlaces":0},"label":"Created","getInitialValue":"default","getUndefinedValue":"default"},{"name":"user_json","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"User Json","getInitialValue":"default","getUndefinedValue":"default"},{"name":"instanceDatastoreConfig","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"Instance Datastore Config","getInitialValue":"default","getUndefinedValue":"default"},{"name":"username","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"User","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":16,"indexes":[],"allidsShardFactor":1,"collectionName":"sessions","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[{"name":"allinstances","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":23},{"name":"sessions_by_user","type":"index","map":"return {username:record.username};","filter":"","indexType":"ancestor","getShardName":"return record.username.substring(0,2)","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[16],"nodeId":24},{"name":"user_name_lookup","type":"index","map":"return {name:record.name, instanceDatastoreConfig:instance.datastoreconfig};","filter":"","indexType":"ancestor","getShardName":"return record.name.substring(0,2)","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[8],"nodeId":25},{"name":"all_versions","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[3],"nodeId":26}],"allidsShardFactor":64,"collectionName":"applications","isSingle":false},{"name":"mastersession","type":"record","fields":[{"name":"user_json","type":"string","typeOptions":{"maxLength":10000,"values":null,"allowDeclaredValuesOnly":false},"label":"User Json","getInitialValue":"default","getUndefinedValue":"default"},{"name":"username","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"User","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":17,"indexes":[],"allidsShardFactor":64,"collectionName":"sessions","isSingle":false}],"pathMaps":[],"indexes":[{"name":"all_applications","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[1],"nodeId":22},{"name":"mastersessions_by_user","type":"index","map":"return {username:record.username};","filter":"","indexType":"ancestor","getShardName":"return record.username.substring(0,2)","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[17],"nodeId":27}],"nodeId":0},"actions":{},"triggers":[]} \ No newline at end of file diff --git a/packages/server/appPackages/testApp/dist/package.tar.gz b/packages/server/appPackages/testApp/dist/package.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..3d913d83a555ee21a2053252f8213a9c7f2e8b23 GIT binary patch literal 1500 zcmV<21ta<&iwFP!000003hi3mbJ{o%@1NrFQ#-?f4FOW_sh7;%?BNv|NT~$ZG2OL@rPwugTcU%zcBK@>cQ^yt^S48 zv+bc_S;L;yHD2{kpxdiRgouMGb@}9tdm#h4E*8R}_yJSV{zovsc^NzQzi;;k>HZHP z1PsgW4lm^T=2h7oKluJXn`-OL(U)h_M{{hBO!nwwZnn$-^EnZMFkelFi$G4h9HS5$ z9J`Eru*_#3{sS*yrh|fj5*LM%q+|c|OuVJJY-N;D;2lWmVTuo<1ZBNL=&D)Si3H}N zb6L~mt!%2KtjhE=>$Mpoj1GP14K?j$0< zho9DI=17DPISHjRSvV4v_Mt?SI=X-NqAA!9;FG2Jp*#-Ke+wczvPe6Wv9D23!zL$9 z$U}MLaZi;Chxtx;PlS_BAId(57b|hjlyM~@S<<|O)P@29kDNeCgm@lMNGVZ}oca9~ zI5Ywz#G}lI&E=96Cu_ar3>)D8+7=bBi=m%E_}GFUKu2b>qlde(P@cJn{oF;~GziPvn+>0ZRMdb~Tb~yHDZ$iRJ6gs+ z*+LO=;?I)j_kpU@pv4?L{fYfqcyEsSmIVlcXarz8@*_%HCR8u>c#U0(IQBlrQ}2BW z>Q50Bc-b;3nqUg-Zj>Cv} zvBq~1jWcYlI@lY}99_1Qd(!vP51#mVkGS_M>^kGXdT=2jI_u7ES2-YEMZ`ylW{R^t zFWsc(;2S{Wd%*ASE;Z7gxWUX=o#-lN#{LJP-MR5Ov#W`!i$Xa5GZ~Nml*~>Sc-N_5 z<0_SWqD=4VnZ8!Z3ZN?UM|$F&qaY5YFyg-P+-|p3DldPIlbMEC0)?4~_pYJ z67WdgFdnMNQ{37_Vgs7ZIG#Zl@f&ARu)-zwh`qab-EC}A&OW=pEXFUp0K9ap-wt2} zsni^P)h+SOBtn4PuW4;jIU;lrJ$gtqQ5B)tc>@nOuABm6_@~%v-JXqxmH3-}U4qeiEye^y*Xc@OEuL zox(1eBl>|Ni60|NOOC5dR0F9QU&+dAlS;6nkmNvI`6Mseeiuzu*))i=qIXrj+Sals z?Wc_<%kKIPRmT0=8+1D8wFkRT2Sq8Iev~Lk;hiE2(LQ%NYXAU`5A0pN_v&q8*Xona z4ujGtON&^+Z?mDh$bp{Ut6v2o2Hy#4|FeF#?;YN%H(XNx z_a$ezyW|vxO?l0cH_3mYG-it{jFXGJ7m;VSo@d={+3{o4nxXEC;Zl2&Jvwr=(=14z z&E)+hFg$-cKF;un2#+me@BjbqTUKv4G%VY)?ZNr~zt7`5&f`3eIsOB1`hTMUGynjw Ce)ehr literal 0 HcmV?d00001 diff --git a/packages/server/config.js b/packages/server/config.js index 693539def..b42293059 100644 --- a/packages/server/config.js +++ b/packages/server/config.js @@ -8,6 +8,6 @@ module.exports = () => ({ keys: ["secret1", "secret2"], port: 4001, latestAppsPath: "./appPackages", - masterPlugins: {}, + extraMasterPlugins: {}, customizeMaster: appDefinition => appDefinition }) \ No newline at end of file diff --git a/packages/server/config.sample.js b/packages/server/config.sample.js index 7e585186e..355c29d3a 100644 --- a/packages/server/config.sample.js +++ b/packages/server/config.sample.js @@ -18,10 +18,10 @@ module.exports = () => ({ port: 4001, // path to where your appDefinition etc is stored (dev time) - latestAppsPath: "./appPackages", + latestAppsPath: "./", // register plugins for master - masterPlugins: {}, + extraMasterPlugins: {}, // make modifications to master's appdefinition - e.g. add plugins customizeMaster: appDefinition => appDefinition diff --git a/packages/server/initialise/createInstanceDb.js b/packages/server/initialise/createInstanceDb.js new file mode 100644 index 000000000..a5486abe1 --- /dev/null +++ b/packages/server/initialise/createInstanceDb.js @@ -0,0 +1,42 @@ +const { + initialiseData, + setupDatastore +} = require("budibase-core"); +const constructHierarchy = require("../utilities/constructHierarchy"); +const getDatabaseManager = require("../utilities/databaseManager"); +const { + getApisForUser, + getApisWithFullAccess +} = require("../utilities/budibaseApi"); +const masterDbAppDefinition = require("../appPackages/master/appDefinition.json"); +const masterDbAccessLevels = require("../appPackages/master/access_levels.json"); +const { masterAppPackage } = require("../utilities/createAppPackage"); + +module.exports = async (datastoreModule, rootDatastoreConfig, appId, instanceId) => { + try { + + const databaseManager = getDatabaseManager( + datastoreModule, rootDatastoreConfig); + + await databaseManager.createEmptyInstanceDb( + appId, instanceId); + + const dbConfig = databaseManager.getInstanceDatastoreConfig( + appId, instanceId); + + const datastore = setupDatastore( + datastoreModule.getDatastore(dbConfig)); + + await initialiseData(datastore, + constructHierarchy(masterDbAppDefinition)); + + return dbConfig; + + } catch(e) { + throw e; + } +}; + + + + diff --git a/packages/server/initialise/createMasterDb.js b/packages/server/initialise/createMasterDb.js index 67a34ddca..c8affcf32 100644 --- a/packages/server/initialise/createMasterDb.js +++ b/packages/server/initialise/createMasterDb.js @@ -1,14 +1,14 @@ -const {initialiseData, setupDatastore, - getTemplateApi} = require("budibase-core"); +const {initialiseData, setupDatastore} = require("budibase-core"); +const constructHierarchy = require("../utilities/constructHierarchy"); const getDatabaseManager = require("../utilities/databaseManager"); const {getApisForUser, getApisWithFullAccess} = require("../utilities/budibaseApi"); const masterDbAppDefinition = require("../appPackages/master/appDefinition.json"); const masterDbAccessLevels = require("../appPackages/master/access_levels.json"); const { masterAppPackage } = require("../utilities/createAppPackage"); -module.exports = async (datastoreModule, rootConfig, username, password) => { +module.exports = async (datastoreModule, rootDatastoreConfig, username, password, budibaseConfig) => { try { - const databaseManager = getDatabaseManager(datastoreModule, rootConfig); + const databaseManager = getDatabaseManager(datastoreModule, rootDatastoreConfig); await databaseManager.createEmptyMasterDb(); const masterDbConfig = databaseManager.masterDatastoreConfig; @@ -16,23 +16,18 @@ module.exports = async (datastoreModule, rootConfig, username, password) => { datastoreModule.getDatastore(masterDbConfig) ); - const templateApi = getTemplateApi({datastore}); - - await initialiseData(datastore, { - hierarchy:templateApi.constructHierarchy(masterDbAppDefinition.hierarchy), - actions:masterDbAppDefinition.actions, - triggers:masterDbAppDefinition.triggers - }); + await initialiseData(datastore, + constructHierarchy(masterDbAppDefinition)); const bbMaster = await getApisWithFullAccess( - datastore, masterAppPackage()); + datastore, masterAppPackage(budibaseConfig)); await bbMaster.authApi.saveAccessLevels(masterDbAccessLevels); const user = bbMaster.authApi.getNewUser(); user.name = username; user.accessLevels= ["owner"]; await bbMaster.authApi.createUser(user, password); - return await getApisForUser(datastore, masterAppPackage(), username, password); + return await getApisForUser(datastore, masterAppPackage(budibaseConfig), username, password); } catch(e) { throw e; } diff --git a/packages/server/initialise/initialiseBudibase.js b/packages/server/initialise/initialiseBudibase.js index a9eb0234a..b741a1748 100644 --- a/packages/server/initialise/initialiseBudibase.js +++ b/packages/server/initialise/initialiseBudibase.js @@ -1,12 +1,11 @@ const create = require("./createMasterDb"); const argv = require("yargs").argv - const readline = require('readline'); const { promisify } = require('util'); -const rimraf = promisify(require("rimraf")); -const fs = require("fs") +const { mkdir, rimraf } = require("../utilities/fsawait"); +const budibaseConfig = require("../config"); + -const mkdir = promisify(fs.mkdir); readline.Interface.prototype.question[promisify.custom] = function(prompt) { return new Promise(resolve => @@ -72,5 +71,6 @@ const question = async (q) => { datastoreModule, rootconfig, username, - password) + password, + budibaseConfig) })() \ No newline at end of file diff --git a/packages/server/initialise/initialiseRuntimePackages.js b/packages/server/initialise/initialiseRuntimePackages.js index eec37b7cf..5ff7807f0 100644 --- a/packages/server/initialise/initialiseRuntimePackages.js +++ b/packages/server/initialise/initialiseRuntimePackages.js @@ -1,21 +1,7 @@ -const util = require("util"); -const fs = require("fs"); -const { join } = require("path"); const { ncp } = require('ncp'); const { masterAppPackage } = require("../utilities/createAppPackage"); -const rimraf = util.promisify(require("rimraf")); -const mkdir = util.promisify(fs.mkdir); - -const exists = root => async (path) => { - try { - await util.promisify(fs.access)( - join(root,path) - ); - } catch (e) { - return false; - } - return true; -}; +const { mkdir, rimraf, exists } = require("../utilities/fsawait"); +const { runtimePackagesDirectory } = require("../utilities/runtimePackages"); const copyfolder = (source, destination) => new Promise((resolve, reject) => { @@ -28,20 +14,20 @@ const copyfolder = (source, destination) => }); }); + module.exports = async (config, bbMaster, latestAppsFolder) => { - const appsRuntimeFolder = "./runtime_apps"; // create runtime folder // copy master into /master/latest - if(await exists(appsRuntimeFolder)) { + if(await exists(runtimePackagesDirectory)) { try { - await rimraf(appsRuntimeFolder); + await rimraf(runtimePackagesDirectory); } catch(err) { console.log(err); } } - await mkdir(appsRuntimeFolder); + await mkdir(runtimePackagesDirectory); /* diff --git a/packages/server/middleware/routers.js b/packages/server/middleware/routers.js index d06b89f4d..7d378bd11 100644 --- a/packages/server/middleware/routers.js +++ b/packages/server/middleware/routers.js @@ -1,6 +1,8 @@ -const Router = require("koa-router"); +const Router = require("@koa/router"); const session = require("./session"); const StatusCodes = require("../utilities/statusCodes"); +const fs = require("fs"); + module.exports = (config, app) => { const router = new Router(); @@ -148,21 +150,30 @@ module.exports = (config, app) => { ); ctx.response.status = StatusCodes.OK; }) - .post("/:appname/api/record/:recordkey", async (ctx) => { + .post("/:appname/api/files/*", async (ctx) => { + const file = ctx.request.files.file; + ctx.body = await ctx.instance.recordApi.uploadFile( + getRecordKey(ctx.params.appname, ctx.request.path), + fs.createReadStream(file.path), + file.name + ); + ctx.response.status = StatusCodes.OK; + }) + .post("/:appname/api/record/*", async (ctx) => { ctx.body = await ctx.instance.recordApi.save( ctx.request.body ); ctx.response.status = StatusCodes.OK; }) - .get("/:appname/api/record/:recordkey", async (ctx) => { + .get("/:appname/api/record/*", async (ctx) => { ctx.body = await ctx.instance.recordApi.load( - ctx.params.recordKey + getRecordKey(ctx.params.appname, ctx.request.path) ); ctx.response.status = StatusCodes.OK; }) - .del("/:appname/api/record/:recordkey", async (ctx) => { + .del("/:appname/api/record/*", async (ctx) => { await ctx.instance.recordApi.delete( - ctx.params.recordKey + getRecordKey(ctx.params.appname, ctx.request.path) ); ctx.response.status = StatusCodes.OK; }) @@ -185,6 +196,11 @@ module.exports = (config, app) => { ctx.response.status = StatusCodes.OK; }); + const getRecordKey = (appname, wholePath) => + wholePath + .replace(`/${appname}/api/record/`, "") + .replace(`/${appname}/api/files/`, ""); + return router; } diff --git a/packages/server/package.json b/packages/server/package.json index d3049454b..4ddcc479b 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -12,14 +12,16 @@ "author": "Michael Shanks", "license": "AGPL-3.0-or-later", "dependencies": { + "@koa/router": "^8.0.0", "argon2": "^0.23.0", "budibase-core": "file:../core/dist", "koa": "^2.7.0", - "koa-bodyparser": "^4.2.1", - "koa-router": "^7.4.0", + "koa-body": "^4.1.0", "koa-session": "^5.12.0", "ncp": "^2.0.0", "rimraf": "^2.6.3", + "tar-fs": "^2.0.0", + "uuid": "^3.3.2", "yargs": "^13.2.4" }, "devDependencies": { diff --git a/packages/server/tests/all.spec.js b/packages/server/tests/all.spec.js index 661da06f6..bdee95396 100644 --- a/packages/server/tests/all.spec.js +++ b/packages/server/tests/all.spec.js @@ -1,10 +1,12 @@ const app = require("./testApp")(); const authenticateMaster = require("./authenticate"); +const createNewApp = require("./createNewApp"); beforeAll(async () => await app.start()) afterAll(async () => await app.destroy()) describe("authenticateMaster", () => authenticateMaster(app)); +describe("createNewApp", () => createNewApp(app)); diff --git a/packages/server/tests/authenticate.js b/packages/server/tests/authenticate.js index 385c07c62..9937de9e1 100644 --- a/packages/server/tests/authenticate.js +++ b/packages/server/tests/authenticate.js @@ -1,7 +1,6 @@ const statusCodes = require("../utilities/statusCodes"); -const util = require("util"); -const fs = require("fs"); -const readFile = util.promisify(fs.readFile); +const { readFile } = require("../utilities/fsawait"); +const { timeout } = require("./helpers"); module.exports = (app) => { @@ -31,7 +30,6 @@ module.exports = (app) => { }); - let ownerCookie; it("should return ok correct username and password supplied", async () => { const response = await app.post("/_master/api/authenticate", { @@ -40,7 +38,7 @@ module.exports = (app) => { }) .expect(statusCodes.OK); - ownerCookie = response.header['set-cookie']; + app.masterAuth.cookie = response.header['set-cookie']; }); const testUserName = "test_user"; @@ -56,7 +54,7 @@ module.exports = (app) => { }, password: testPassword }) - .set("cookie", ownerCookie) + .set("cookie", app.masterAuth.cookie) .expect(statusCodes.OK); @@ -74,7 +72,7 @@ module.exports = (app) => { newUserCookie = responseNewUser.header['set-cookie']; expect(newUserCookie).toBeDefined(); - expect(newUserCookie).not.toEqual(ownerCookie); + expect(newUserCookie).not.toEqual(app.masterAuth.cookie); app.get("/_master/api/users/") .set("cookie", newUserCookie) @@ -86,7 +84,7 @@ module.exports = (app) => { await app.post("/_master/api/disableUser", { username: testUserName }) - .set("cookie", ownerCookie) + .set("cookie", app.masterAuth.cookie) .expect(statusCodes.OK); await app.get("/_master/api/users/") @@ -114,7 +112,7 @@ module.exports = (app) => { await app.post("/_master/api/enableUser", { username: testUserName }) - .set("cookie", ownerCookie) + .set("cookie", app.masterAuth.cookie) .expect(statusCodes.OK); await app.post("/_master/api/authenticate", { @@ -124,8 +122,9 @@ module.exports = (app) => { .expect(statusCodes.OK); }); + let testUserTempCode; it("should be able to reset password with temporary access", async () => { - // need to sort out behaviour sources for this... + await app.post("/_master/api/createTemporaryAccess", { username: testUserName }) @@ -133,11 +132,15 @@ module.exports = (app) => { testPassword = "test_user_new_password"; - const tempCode = await readFile(`./tests/.data/tempaccess${testUserName}`, "utf8"); + // the behaviour that creates the below file is async, + /// to this timeout is giving it a change to work its magic + await timeout(10); + const testUserTempCode = await readFile(`./tests/.data/tempaccess${testUserName}`, "utf8"); + await app.post("/_master/api/setPasswordFromTemporaryCode", { username: testUserName, - tempCode, + tempCode:testUserTempCode, newPassword:testPassword }) .expect(statusCodes.OK); @@ -148,5 +151,30 @@ module.exports = (app) => { }) .expect(statusCodes.OK); + + + }); + + it("should not be able to set password with used temp code", async () => { + + await app.post("/_master/api/setPasswordFromTemporaryCode", { + username: testUserName, + tempCode:testUserTempCode, + newPassword:"whatever" + }) + .expect(statusCodes.OK); + + await app.post("/_master/api/authenticate", { + username: testUserName, + password: "whatever" + }) + .expect(statusCodes.UNAUTHORIZED); + + await app.post("/_master/api/authenticate", { + username: testUserName, + password: testPassword + }) + .expect(statusCodes.OK); + }); }; diff --git a/packages/server/tests/createNewApp.js b/packages/server/tests/createNewApp.js new file mode 100644 index 000000000..8d216e3b5 --- /dev/null +++ b/packages/server/tests/createNewApp.js @@ -0,0 +1,72 @@ +const statusCodes = require("../utilities/statusCodes"); +const constructHierarchy = require("../utilities/constructHierarchy"); +const { readFile } = require("../utilities/fsawait"); +const {getRecordApi, getAuthApi} = require("budibase-core"); +const masterAppDefinition = constructHierarchy( + require("../appPackages/master/appDefinition.json")); +const {getApisWithFullAccess} = require("../utilities/budibaseApi"); +const { createTarGzPackage } = require("../utilities/targzAppPackage"); + +module.exports = (app) => { + + let _master; + const getmaster = async () => { + if(!_master) + _master = await getApisWithFullAccess({}, app.masterAppPackage); + return _master; + } + + let newAppKey = ""; + it("create new application should be successful for owner", async () => { + const master = await getmaster(); + const newApp = master.recordApi.getNew("/applications", "application"); + newApp.name = app.testAppInfo.name + newAppKey = newApp.key; + + await app.post(`/_master/api/record/${newApp.key}`, newApp) + .set("cookie", app.masterAuth.cookie) + .expect(statusCodes.OK); + + const response = await app.get(`/_master/api/record/${newApp.key}`) + .set("cookie", app.masterAuth.cookie) + .expect(statusCodes.OK); + + expect(response.body.name).toBe(newApp.name); + }); + + let version1Key = ""; + it("should be able to upload new version including package files", async () => { + const master = await getmaster(); + const version1 = master.recordApi + .getNew(`${newAppKey}/versions`, "version"); + version1.name = "v1"; + version1Key = version1.key; + + const { path, size } = await createTarGzPackage(app.config, "testApp"); + + version1.package = { relativePath: "package.tar.gz", size}; + + await app.post(`/_master/api/record/${version1.key}`, version1) + .set("cookie", app.masterAuth.cookie) + .expect(statusCodes.OK); + + await app.post(`/_master/api/files/${version1.key}`) + .attach("file", path, "package.tar.gz") + .set("cookie", app.masterAuth.cookie) + .expect(statusCodes.OK); + + }); + + it("should be able to create new instance of app", async () => { + const master = await getmaster(); + const instance1 = master.recordApi + .getNew(`${newAppKey}/instances`, "instance"); + instance1.name = "instance 1"; + instance1.active = true; + instance1.version = {key:version1Key, name:"v1"}; + instance1.datastoreconfig; + + + }); + +} \ No newline at end of file diff --git a/packages/server/tests/helpers.js b/packages/server/tests/helpers.js new file mode 100644 index 000000000..01c728dae --- /dev/null +++ b/packages/server/tests/helpers.js @@ -0,0 +1,9 @@ + + +module.exports.timeout = ms => + new Promise(resolve => setTimeout(resolve, ms)); + +module.exports.sleep = async (ms, fn) => { + await timeout(ms); + return await fn(...args); +} \ No newline at end of file diff --git a/packages/server/tests/testApp.js b/packages/server/tests/testApp.js index f4a284a28..93c37a281 100644 --- a/packages/server/tests/testApp.js +++ b/packages/server/tests/testApp.js @@ -1,16 +1,16 @@ const app = require("../app"); -const { promisify } = require("util"); -const rimraf = promisify(require("rimraf")); +const { rimraf, mkdir } = require("../utilities/fsawait"); const createMasterDb = require("../initialise/createMasterDb"); const request = require("supertest"); const fs = require("fs"); +const { masterAppPackage } = require("../utilities/createAppPackage"); + var enableDestroy = require('server-destroy'); -const mkdir = promisify(fs.mkdir); const masterOwnerName = "test_master"; const masterOwnerPassword = "test_master_pass"; -const masterPlugins = { +const extraMasterPlugins = { main: { outputToFile : ({filename, content}) => { fs.writeFile(`./tests/.data/${filename}`, content, {encoding:"utf8"}); @@ -44,7 +44,8 @@ const config = { }, keys: ["secret1", "secret2"], port: 4002, - masterPlugins, + latestAppsPath: "./appPackages", + extraMasterPlugins, customizeMaster } @@ -69,12 +70,19 @@ module.exports = () => { get: (url) => getRequest(server, url), masterAuth: { username: masterOwnerName, - password: masterOwnerPassword + password: masterOwnerPassword, + cookie: "" + }, + testAppInfo: { + name: "testApp" }, - destroy: () => server.destroy() + destroy: () => server.destroy(), + masterAppPackage: masterAppPackage(config) }) }; + + const postRequest = (server, url, body) => request(server) .post(url) @@ -98,7 +106,8 @@ const reInitialize = async () => { datastoreModule, config.datastoreConfig, masterOwnerName, - masterOwnerPassword + masterOwnerPassword , + config ); } diff --git a/packages/server/utilities/constructHierarchy.js b/packages/server/utilities/constructHierarchy.js new file mode 100644 index 000000000..1d444eaa9 --- /dev/null +++ b/packages/server/utilities/constructHierarchy.js @@ -0,0 +1,6 @@ +const {getTemplateApi} = require("budibase-core"); +const templateApi = getTemplateApi({}); +module.exports = (appDefinition) => { + appDefinition.hierarchy = templateApi.constructHierarchy(appDefinition.hierarchy); + return appDefinition; +} \ No newline at end of file diff --git a/packages/server/utilities/createAppPackage.js b/packages/server/utilities/createAppPackage.js index ff29b2dc8..8224588cd 100644 --- a/packages/server/utilities/createAppPackage.js +++ b/packages/server/utilities/createAppPackage.js @@ -1,8 +1,9 @@ const { join } = require("path"); - +const constructHierarchy = require("./constructHierarchy"); +const { common } = require("budibase-core"); const createAppPackage = (appPath) => ({ appDefinition: require(join(appPath, "appDefinition.json")), - behaviourSources: require(join(appPath, "plugins.json")), + behaviourSources: require(join(appPath, "plugins.js")), appPath }); @@ -13,19 +14,25 @@ module.exports.masterAppPackage = (config) => { ? config.customizeMaster : a => a; - const appDefinition = customizeMaster( - standardPackage.appDefinition); + const appDefinition = common.$(standardPackage.appDefinition, [ + customizeMaster, + constructHierarchy + ]); + + const plugins = require("../appPackages/master/plugins.js") + (config); return ({ appDefinition, - behaviourSources: config && config.masterPlugins - ? config.masterPlugins - : standardPackage.behaviourSources, + behaviourSources: config && config.extraMasterPlugins + ? {...plugins, ...config.extraMasterPlugins} + : plugins, appPath: standardPackage.appPath }); } -module.exports.applictionVersionPackage = (appname, versionId) => - createAppPackage(`../runtimePackages/${appname}/${versionId}`); - - +module.exports.applictionVersionPackage = (appname, versionId) => { + const pkg = createAppPackage(`../runtimePackages/${appname}/${versionId}`); + pkg.appDefinition = constructHierarchy(appDefinition); + return pkg; +} diff --git a/packages/server/utilities/fsawait.js b/packages/server/utilities/fsawait.js new file mode 100644 index 000000000..b2c99adc2 --- /dev/null +++ b/packages/server/utilities/fsawait.js @@ -0,0 +1,19 @@ +const util = require("util"); +const fs = require("fs"); + +module.exports.readFile = util.promisify(fs.readFile); +module.exports.rimraf = util.promisify(require("rimraf")); +module.exports.mkdir = util.promisify(fs.mkdir); +module.exports.unlink = util.promisify(fs.unlink); +module.exports.stat = util.promisify(fs.stat); +module.exports.exists = async (path) => { + try { + await util.promisify(fs.access)( + path + ); + } catch (e) { + return false; + } + return true; +}; + diff --git a/packages/server/utilities/runtimePackages.js b/packages/server/utilities/runtimePackages.js new file mode 100644 index 000000000..d7859d489 --- /dev/null +++ b/packages/server/utilities/runtimePackages.js @@ -0,0 +1,8 @@ +const { join } = require("path"); + +const runtimePackagesDirectory = "./runtime_apps"; + +module.exports.runtimePackagesDirectory = runtimePackagesDirectory; + +module.exports.getRuntimePackageDirectory = (appName, versionId) => + join(runtimePackagesDirectory, appName, versionId); diff --git a/packages/server/utilities/statusCodes.js b/packages/server/utilities/statusCodes.js index 0f6d229d5..84f2a5497 100644 --- a/packages/server/utilities/statusCodes.js +++ b/packages/server/utilities/statusCodes.js @@ -2,5 +2,6 @@ module.exports = { OK:200, UNAUTHORIZED:401, FORBIDDEN:403, - NOT_FOUND:404 + NOT_FOUND:404, + INTERAL_ERROR:500 }; \ No newline at end of file diff --git a/packages/server/utilities/targzAppPackage.js b/packages/server/utilities/targzAppPackage.js new file mode 100644 index 000000000..684457fa3 --- /dev/null +++ b/packages/server/utilities/targzAppPackage.js @@ -0,0 +1,91 @@ +// Based on https://github.com/lafin/node-targz +// MIT license + +const fs = require("fs"); +const tar = require('tar-fs'); +const zlib = require("zlib"); +const { join, dirname, sep } = require("path"); +const { exists, mkdir, unlink, stat } = require("../utilities/fsawait"); +const { getRuntimePackageDirectory } = require("./runtimePackages"); + +module.exports.createTarGzPackage = async (config, appName) => { + + const appPath = join(config.latestAppsPath, appName); + const distPath = join(appPath, "dist"); + + if(!await exists(distPath)) { + await mkdir(distPath); + } + + const packagePath = `${distPath}/package.tar.gz`; + if(await exists(`${packagePath}`)) { + await unlink(packagePath); + } + + await compress(appPath, packagePath); + const size = (await stat(packagePath)).size; + return {size, path:packagePath}; +} + +module.exports.unzipTarGzPackageToRuntime = async (src, appName, versionId) => { + const versionDir = getRuntimePackageDirectory(appName, versionId); + + if(await exists(versionDir)) { + await rimraf(versionDir); + } + + await mkdir(versionDir); + + decompress(src, versionDir); +} + +const compress = (src, dest) => new Promise((resolve, reject) => { + + // ensure opts + opts = {src, dest}; + opts.tar = {ignore: name => dirname(name).split(sep).pop() === "dist"}; + opts.gz = opts.gz || {}; + + // default gzip config + opts.gz.level = opts.gz.level || 6; + opts.gz.memLevel = opts.gz.memLevel || 6; + + // ensure src and dest + if(!opts.src) return reject("No source for compress!"); + if(!opts.dest) return reject("No destination for compress!"); + + // go + process.nextTick(function () { + tar.pack(opts.src, opts.tar) + .on('error', reject) + .pipe(zlib.createGzip(opts.gz) + .on('error', reject)) + .pipe(fs.createWriteStream(opts.dest) + .on('error', reject) + .on('finish', resolve)); + }); +}); + +const decompress = (src, dest) => new Promise((resolve, reject) => { + + // ensure opts + opts = {src, dest}; + opts.tar = opts.tar || {}; + opts.gz = opts.gz || {}; + + // ensure src and dest + if(!opts.src) return reject("No source for decompress!"); + if(!opts.dest) return reject("No destination for decompress!"); + + // go + process.nextTick(function () { + fs.createReadStream(opts.src) + .on('error', reject) + .pipe(zlib.createGunzip(opts.gz) + .on('error', reject)) + .pipe(tar.extract(opts.dest, opts.tar) + .on('error', reject) + .on('finish', resolve)); + }); +}); + diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 42d207dc6..a755e7449 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -285,6 +285,18 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^12.0.9" +"@koa/router@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@koa/router/-/router-8.0.0.tgz#fd4ffa6f03d8293a04c023cb4a22b612401fbe70" + integrity sha512-P70CGOGs6JPu/mnrd9lt6ESzlBXLHT/uTK8+5U4M7Oapt8la/tiZv2c7X9jq0ksFsM59RH3AwJYzKOuavDcjIw== + dependencies: + debug "^3.1.0" + http-errors "^1.3.1" + koa-compose "^3.0.0" + methods "^1.0.1" + path-to-regexp "^1.1.1" + urijs "^1.19.0" + "@nx-js/compiler-util@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@nx-js/compiler-util/-/compiler-util-2.0.0.tgz#c74c12165fa2f017a292bb79af007e8fce0af297" @@ -330,6 +342,19 @@ dependencies: "@babel/types" "^7.3.0" +"@types/events@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + +"@types/formidable@^1.0.31": + version "1.0.31" + resolved "https://registry.yarnpkg.com/@types/formidable/-/formidable-1.0.31.tgz#274f9dc2d0a1a9ce1feef48c24ca0859e7ec947b" + integrity sha512-dIhM5t8lRP0oWe2HF8MuPvdd1TpPTjhDMAqemcq6oIZQCBQTovhBAdTQ5L5veJB4pdQChadmHuxtB0YzqvfU3Q== + dependencies: + "@types/events" "*" + "@types/node" "*" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" @@ -350,6 +375,11 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" +"@types/node@*": + version "12.0.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.10.tgz#51babf9c7deadd5343620055fc8aff7995c8b031" + integrity sha512-LcsGbPomWsad6wmMNv7nBLw7YYYyfdYcz6xryKYQhx89c3XXan+8Q6AJ43G5XDIaklaVkK3mE4fCb0SBvMiPSQ== + "@types/stack-utils@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" @@ -612,6 +642,13 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +bl@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88" + integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A== + dependencies: + readable-stream "^3.0.1" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -776,15 +813,15 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" -co-body@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/co-body/-/co-body-6.0.0.tgz#965b9337d7f5655480787471f4237664820827e3" - integrity sha512-9ZIcixguuuKIptnY8yemEOuhb71L/lLf+Rl5JfJEUiDNJk0e02MBt7BPxR2GEh5mw8dPthQYR4jPI/BnS1MQgw== +co-body@^5.1.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/co-body/-/co-body-5.2.0.tgz#5a0a658c46029131e0e3a306f67647302f71c124" + integrity sha512-sX/LQ7LqUhgyaxzbe7IqwPeTr2yfpfUIQ/dgpKo6ZI4y4lpQA0YxAomWIY+7I7rHWcG02PG+OuPREzMW/5tszQ== dependencies: inflation "^2.0.0" - qs "^6.5.2" - raw-body "^2.3.3" - type-is "^1.6.16" + qs "^6.4.0" + raw-body "^2.2.0" + type-is "^1.6.14" co@^4.6.0: version "4.6.0" @@ -880,11 +917,6 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-to@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/copy-to/-/copy-to-2.0.1.tgz#2680fbb8068a48d08656b6098092bdafc906f4a5" - integrity sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU= - core-util-is@1.0.2, core-util-is@^1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -1083,7 +1115,7 @@ emoji-regex@^7.0.1: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== -end-of-stream@^1.1.0: +end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== @@ -1310,7 +1342,7 @@ form-data@^2.3.1, form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -formidable@^1.2.0: +formidable@^1.1.1, formidable@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659" integrity sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg== @@ -1327,6 +1359,11 @@ fresh@~0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs-minipass@^1.2.5: version "1.2.6" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" @@ -1519,7 +1556,18 @@ http-assert@^1.3.0: deep-equal "~1.0.1" http-errors "~1.7.2" -http-errors@1.7.2, http-errors@^1.3.1, http-errors@^1.6.3, http-errors@~1.7.2: +http-errors@1.7.3, http-errors@^1.3.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@^1.6.3, http-errors@~1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== @@ -1589,6 +1637,11 @@ inherits@2, inherits@2.0.3, inherits@~2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +inherits@2.0.4, inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" @@ -2322,13 +2375,14 @@ kleur@^3.0.2: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -koa-bodyparser@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/koa-bodyparser/-/koa-bodyparser-4.2.1.tgz#4d7dacb5e6db1106649b595d9e5ccb158b6f3b29" - integrity sha512-UIjPAlMZfNYDDe+4zBaOAUKYqkwAGcIU6r2ARf1UOXPAlfennQys5IiShaVeNf7KkVBlf88f2LeLvBFvKylttw== +koa-body@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/koa-body/-/koa-body-4.1.0.tgz#99295ee2e9543884e5730ae696780930b3821c44" + integrity sha512-rWkMfMaCjFmIAMohtjlrg4BqDzcotK5BdZhiwJu1ONuR1ceoFUjnH3wp0hEV39HuBlc9tI3eUUFMK4Cp6ccFtA== dependencies: - co-body "^6.0.0" - copy-to "^2.0.1" + "@types/formidable" "^1.0.31" + co-body "^5.1.1" + formidable "^1.1.1" koa-compose@^3.0.0: version "3.2.1" @@ -2355,18 +2409,6 @@ koa-is-json@^1.0.0: resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" integrity sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ= -koa-router@^7.4.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/koa-router/-/koa-router-7.4.0.tgz#aee1f7adc02d5cb31d7d67465c9eacc825e8c5e0" - integrity sha512-IWhaDXeAnfDBEpWS6hkGdZ1ablgr6Q6pGdXCyK38RbzuH4LkUOpPqPw+3f8l8aTDrQmBQ7xJc0bs2yV4dzcO+g== - dependencies: - debug "^3.1.0" - http-errors "^1.3.1" - koa-compose "^3.0.0" - methods "^1.0.1" - path-to-regexp "^1.1.1" - urijs "^1.19.0" - koa-session@^5.12.0: version "5.12.0" resolved "https://registry.yarnpkg.com/koa-session/-/koa-session-5.12.0.tgz#1e6c6cea86b8ca2cca921c4a8881cfbfcc2628e0" @@ -3113,7 +3155,7 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@^6.5.1, qs@^6.5.2: +qs@^6.4.0, qs@^6.5.1: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== @@ -3123,13 +3165,13 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== -raw-body@^2.3.3: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== +raw-body@^2.2.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" + integrity sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA== dependencies: bytes "3.1.0" - http-errors "1.7.2" + http-errors "1.7.3" iconv-lite "0.4.24" unpipe "1.0.0" @@ -3178,6 +3220,15 @@ readable-stream@^2.0.1, readable-stream@^2.0.6, readable-stream@^2.3.5: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^3.0.1, readable-stream@^3.1.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" + integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + realpath-native@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" @@ -3601,7 +3652,7 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string_decoder@^1.2.0: +string_decoder@^1.1.1, string_decoder@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== @@ -3694,6 +3745,27 @@ symbol-tree@^3.2.2: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== +tar-fs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.0.tgz#677700fc0c8b337a78bee3623fdc235f21d7afad" + integrity sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA== + dependencies: + chownr "^1.1.1" + mkdirp "^0.5.1" + pump "^3.0.0" + tar-stream "^2.0.0" + +tar-stream@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3" + integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw== + dependencies: + bl "^3.0.0" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + tar@^4: version "4.4.10" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" @@ -3809,7 +3881,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-is@^1.6.16: +type-is@^1.6.14, type-is@^1.6.16: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== @@ -3870,7 +3942,7 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=