diff --git a/WebFileSystem.ts b/WebFileSystem.ts index d6fef0d..a3a6ced 100644 --- a/WebFileSystem.ts +++ b/WebFileSystem.ts @@ -296,19 +296,23 @@ class WebFileSystem extends webdav.FileSystem { adder = this.addFileToResources.bind(this) } else { adder = (path: Path, user: User, resource : ResourceResponse) => { + const creationDate = this.rootPath === 'courses' ? new Date(resource.createdAt) : null + const lastModifiedDate = this.rootPath === 'courses' ? new Date(resource.updatedAt) : null + this.resources.get(user.uid).set(path.toString(), { type: webdav.ResourceType.Directory, id: resource._id, size: null, - creationDate: null, - lastModifiedDate: null, + creationDate: this.rootPath === 'courses' ? creationDate.getTime() : null, + lastModifiedDate: this.rootPath === 'courses' ? lastModifiedDate.getTime() : null, permissions: null }); } } for (const resource of data.data) { - adder(new Path([resource.name]), user, resource) + const childPath: Path = new Path([resource.name]) + adder(childPath, user, resource) // TODO: Maybe can be integrated more beautiful if (this.rootPath === 'teams') { @@ -316,7 +320,12 @@ class WebFileSystem extends webdav.FileSystem { logger.debug(`response Data on load teams: ${res.data}`) - this.resources.get(user.uid).get('/' + resource.name).role = res.data.user.role + const creationDate = new Date(res.data.createdAt) + const lastModifiedDate = new Date(res.data.updatedAt) + + this.resources.get(user.uid).get(childPath.toString()).role = res.data.user.role + this.resources.get(user.uid).get(childPath.toString()).creationDate = creationDate.getTime() + this.resources.get(user.uid).get(childPath.toString()).lastModifiedDate = lastModifiedDate.getTime() } } @@ -377,12 +386,6 @@ class WebFileSystem extends webdav.FileSystem { logger.debug(`Load Directory Response Data: ${JSON.stringify(data)}`) - if (this.rootPath === 'teams') { - const teamRes = await api({user}).get('teams/' + owner) - - logger.debug(`Response Data on load Directory in teams: ${JSON.stringify(teamRes.data)}`) - } - const resources = [] for (const resource of data) { this.addFileToResources(path.getChildPath(resource.name), user, resource) @@ -529,6 +532,44 @@ class WebFileSystem extends webdav.FileSystem { throw webdav.Errors.Forbidden } + /* + * Updates the 'updatedAt'-attribute of the parent directories to time of execution + * + * @param {Path} path Path to resource + * @param {User} user Current user + */ + async updateParentModifiedDates (path: Path, user: User): Promise { + // TODO: This method and its senders can be deleted as soon as https://github.com/hpi-schul-cloud/schulcloud-server/pull/2102 gets merged + + /* + logger.info('Updating \'updatedAt\' of parent directories...') + + let parentPath = path.getParent() + let parentID = this.getID(parentPath, user) + while (!parentPath.isRoot()) { + if (parentPath.hasParent() || (this.rootPath !== 'courses' && this.rootPath !== 'teams')) { + const res = await api({user, json: true}).patch('/files/' + parentID, { + updatedAt: new Date().toISOString() + }) + + logger.debug(`Update-Response:`) + logger.debug(res.data) + } else { + const res = await api({user, json: true}).patch((this.rootPath === 'courses' ? '/courses/' : '/teams/') + parentID, { + updatedAt: new Date().toISOString() + }) + + logger.debug(`Update-Response:`) + logger.debug(res.data) + } + this.resources.get(user.uid).get(parentPath.toString()).lastModifiedDate = Date.now() + + parentPath = parentPath.getParent() + parentID = this.getID(parentPath, user) + } + */ + } + async _openReadStream (path: Path, info: OpenReadStreamInfo, callback: ReturnCallback) : Promise { logger.info("Reading file: " + path.toString()) @@ -661,9 +702,21 @@ class WebFileSystem extends webdav.FileSystem { logger.info("Checking last modified date: " + path); if (ctx.context.user) { - this.createUserFileSystem(ctx.context.user.uid) - const lastModifiedDate = await this.getMetadata(path, 'lastModifiedDate', ctx.context.user) - if (lastModifiedDate >= 0) { + const user: User = ctx.context.user + + this.createUserFileSystem(user.uid) + + let lastModifiedDate + + if (path.isRoot()) { + const rootResources: string[] = await this.loadRootDirectories(user) + const lastModifiedDates = await Promise.all(rootResources.map(async (resource) => await this.getMetadata(path.getChildPath(resource), 'lastModifiedDate', user))) + lastModifiedDate = Math.max(...lastModifiedDates) + } else { + lastModifiedDate = await this.getMetadata(path, 'lastModifiedDate', user) + } + + if (lastModifiedDate > 0) { callback(null, lastModifiedDate) } else { callback(webdav.Errors.None) @@ -696,7 +749,7 @@ class WebFileSystem extends webdav.FileSystem { this.deleteResourceLocally(path, user) } - if (!this.resources.get(user.uid).get(path.getParent().toString()).permissions || this.canCreate(path.getParent(), user)) { + if (!this.resources.get(user.uid).get(path.getParent().toString())?.permissions || this.canCreate(path.getParent(), user)) { if (type.isDirectory || ['docx', 'pptx', 'xlsx'].includes(mime.extension(mime.lookup(path.fileName())))) { const owner = this.getOwnerID(path, user) const parent = this.getParentID(path.getParent(), user) @@ -746,12 +799,12 @@ class WebFileSystem extends webdav.FileSystem { return error } } + await this.updateParentModifiedDates(path, user) } else { logger.error(`WebFileSystem.createResource.permissions.false : Creating resource not allowed! uid: ${user.uid} path: ${path.toString()}`, new Error('Stack-Tracer')) return webdav.Errors.Forbidden } - return null } @@ -815,6 +868,8 @@ class WebFileSystem extends webdav.FileSystem { this.deleteResourceLocally(path, user) + await this.updateParentModifiedDates(path, user) + return null } else { logger.error(`WebFileSystem.deleteResource.deletePermission.false : Deleting resource not allowed! uid: ${user.uid} path: ${path.toString()}`, new Error('Stack-Tracer')) @@ -975,6 +1030,7 @@ class WebFileSystem extends webdav.FileSystem { if (file._id) { this.addFileToResources(path, user, file) + await this.updateParentModifiedDates(path, user) } else { logger.error(`WebFileSystem.processStream.file._id.false: ${webdav.Errors.Forbidden.message} uid: ${user.uid}`, new Error('Stack-Tracer')) } @@ -984,6 +1040,8 @@ class WebFileSystem extends webdav.FileSystem { updatedAt: new Date().toISOString() }) + await this.updateParentModifiedDates(path, user) + this.resources.get(user.uid).get(path.toString()).size = Buffer.concat(contents).byteLength this.resources.get(user.uid).get(path.toString()).lastModifiedDate = Date.now() @@ -1040,7 +1098,7 @@ class WebFileSystem extends webdav.FileSystem { return await api({user, json: true}).patch( `/fileStorage/${resourceID}`, {parent: newParentID}) - .then((res) => { + .then(async (res) => { logger.debug(`WebFileSystem.moveResource.res.data: ${JSON.stringify(res.data)}`) if (res.data.code === 403) { @@ -1051,6 +1109,9 @@ class WebFileSystem extends webdav.FileSystem { this.resources.get(user.uid).set(pathTo.toString(), this.resources.get(user.uid).get(pathFrom.toString())) this.deleteResourceLocally(pathFrom, user) + await this.updateParentModifiedDates(pathFrom, user) + await this.updateParentModifiedDates(pathTo, user) + return null }).catch((error) => { logger.error(`WebFileSystem.moveResource : File could not be moved ${user.uid}, ${resourceID}, ${newParentID}`, error); @@ -1142,7 +1203,7 @@ class WebFileSystem extends webdav.FileSystem { return await api({user,json:true}).post('/fileStorage' + (type.isDirectory ? '/directories' : '') + '/rename', { id: this.getID(path, user), newName - }).then((res: AxiosResponse) => { + }).then(async (res: AxiosResponse) => { if (res.data.code) { logger.error(`WebFileSystem.renameResource.data.code.${res.data.code}: ${res.data.message} uid: ${user.uid}`, new Error('Stack-Tracer')) if (res.data.code === 403 && res.data.errors?.code === 403) { @@ -1156,6 +1217,8 @@ class WebFileSystem extends webdav.FileSystem { this.resources.get(user.uid).set(path.getParent().getChildPath(newName).toString(), this.resources.get(user.uid).get(path.toString())) this.deleteResourceLocally(path, user) + await this.updateParentModifiedDates(path, user) + logger.info(`File at ${path.toString()} now named ${newName}`) return null diff --git a/config/owncloud.ts b/config/owncloud.ts new file mode 100644 index 0000000..75e81e3 --- /dev/null +++ b/config/owncloud.ts @@ -0,0 +1,157 @@ +import {environment} from './globals'; + +export const onwcloudConfig = { + capabilities : { + "ocs":{ + "meta":{ + "status":"ok", + "statuscode":100, + "message":"OK", + "totalitems":"", + "itemsperpage":"" + }, + "data":{ + "version":{ + "major":10, + "minor":5, + "micro":0, + "string":"10.5.0", + "edition":"Community" + }, + "capabilities":{ + "core":{ + "pollinterval":60, + "webdav-root":environment.WEBDAV_ROOT, + "status":{ + "installed":true, + "maintenance":false, + "needsDbUpgrade":false, + "version":"10.5.0.10", + "versionstring":"10.5.0", + "edition":"Community", + "productname":"HPI-Schul-Cloud", + "hostname":"Schul-Cloud" + } + }, + "checksums":{ + "supportedTypes":[ + "SHA1" + ], + "preferredUploadType":"SHA1" + }, + "files":{ + "privateLinks":true, + "privateLinksDetailsParam":true, + "bigfilechunking":true, + "blacklisted_files":[ + ".htaccess" + ], + "undelete":true, + "versioning":true + }, + "dav":{ + "chunking":"1.0", + "reports":[ + "search-files" + ], + "trashbin":"1.0" + }, + "files_sharing":{ + "api_enabled":true, + "public":{ + "enabled":true, + "password":{ + "enforced_for":{ + "read_only":false, + "read_write":false, + "upload_only":false, + "read_write_delete":false + }, + "enforced":false + }, + "roles_api":true, + "expire_date":{ + "enabled":false + }, + "send_mail":false, + "social_share":true, + "upload":true, + "multiple":true, + "supports_upload_only":true, + "defaultPublicLinkShareName":"Öffentlicher Link" + }, + "user":{ + "send_mail":false, + "expire_date":{ + "enabled":false + } + }, + "group":{ + "expire_date":{ + "enabled":false + } + }, + "resharing":true, + "group_sharing":true, + "auto_accept_share":true, + "share_with_group_members_only":true, + "share_with_membership_groups_only":true, + "can_share":true, + "user_enumeration":{ + "enabled":true, + "group_members_only":false + }, + "default_permissions":31, + "providers_capabilities":{ + "ocinternal":{ + "user":[ + "shareExpiration" + ], + "group":[ + "shareExpiration" + ], + "link":[ + "shareExpiration", + "passwordProtected" + ] + }, + "ocFederatedSharing":{ + "remote":[ + + ] + } + }, + "federation":{ + "outgoing":true, + "incoming":true + }, + "search_min_length":2 + }, + "notifications":{ + "ocs-endpoints":[ + "list", + "get", + "delete" + ] + } + } + } + } + }, + config : { + "ocs":{ + "meta":{ + "status":"ok", + "statuscode":100, + "message":null + }, + "data":{ + "version":"1.7", + "website":"ownCloud", + "host":"localhost", + "contact":"", + "ssl":"false" + } + } + }, +} \ No newline at end of file diff --git a/index.ts b/index.ts index c8590a0..376ff07 100644 --- a/index.ts +++ b/index.ts @@ -4,51 +4,52 @@ import WebFileSystem from "./WebFileSystem"; import UserManager from "./UserManager"; import logger from './logger'; import {environment} from './config/globals'; -import Propfind from "webdav-server/lib/server/v2/commands/Propfind"; +import {onwcloudConfig} from './config/owncloud'; const userManager = new UserManager() const server = new webdav.WebDAVServer({ - httpAuthentication: new webdav.HTTPBasicAuthentication(userManager) - + httpAuthentication: new webdav.HTTPBasicAuthentication(userManager), + respondWithPaths : true }); server.setFileSystem('courses', new WebFileSystem('courses'), (succeeded) => { - if (succeeded) { - logger.info("Successfully mounted 'courses' file system!") - } + if (succeeded) { + logger.info("Successfully mounted 'courses' file system!") + } }); server.setFileSystem('my', new WebFileSystem('my'), (succeeded) => { - if (succeeded) { - logger.info("Successfully mounted 'my files' file system!") - } + if (succeeded) { + logger.info("Successfully mounted 'my files' file system!") + } }); server.setFileSystem('teams', new WebFileSystem('teams'), (succeeded) => { - if (succeeded) { - logger.info("Successfully mounted 'teams' file system!") - } + if (succeeded) { + logger.info("Successfully mounted 'teams' file system!") + } }); server.setFileSystem('shared', new WebFileSystem('shared'), (succeeded) => { - if (succeeded) { - logger.info("Successfully mounted 'shared' file system!") - } + if (succeeded) { + logger.info("Successfully mounted 'shared' file system!") + } }); const app = express() -/* -Calling GET /ocs/v1.php/cloud/capabilities?format=json... -Calling GET /ocs/v1.php/config?format=json... -Calling GET /ocs/v1.php/cloud/user?format=json... -Calling GET /remote.php/dav/avatars/lehrer@schul-cloud.org/128.png... -Calling GET /ocs/v2.php/apps/notifications/api/v2/notifications?format=json... -Calling GET /ocs/v2.php/core/navigation/apps?absolute=true&format=json... - */ +let reqCounter = 0; + +function reqLabler (req,res ,next) { + req.counter = reqCounter; + reqCounter+=1 + next(); +} + +app.use(reqLabler) app.use((req, res, next) => { - logger.info('Calling ' + req.method + ' ' + req.originalUrl + '...') + logger.error('Calling ' + req.method + ' ' + req.originalUrl + ' --> new URL: '+ req.url + ' - Number: ' + String(reqCounter-1)) next() }) @@ -65,60 +66,151 @@ app.get('/nextcloud/status.php', (req, res) => { productname: "HPI Schul-Cloud" }) }) +app.get('/status.php', (req, res) => { + logger.info('Requesting status...') + // TODO: Answer with real data + res.send({ + installed: true, + maintenance: false, + needsDbUpgrade: false, + version: "10.0.3.3", + versionstring: "10.0.3", + edition: "Community", + productname: "HPI Schul-Cloud" + }) +}) + +app.get('/ocs/v1.php/cloud/capabilities', (req, res) => { + logger.info('Requesting v1 capabilities...') + res.send(onwcloudConfig.capabilities) +}) + +// Seems to get requested much earlier, however, nextcloud tries to get /remote.php/webdav +app.get('/ocs/v2.php/cloud/capabilities', (req, res) => { + logger.info('Requesting v2 capabilities...') + res.send(onwcloudConfig.capabilities) +}) + +app.get('/ocs/v2.php/core/navigation/apps', (req, res, next) => { + logger.info('Requesting v2 navigation...') + next() +}) -// TODO: Determine what is needed -const capabilities = { - ocs: { - data: { - capabilities: { - files: { - blacklisted_files : [], - bigfilechunking: false, - privateLinks: false, - privateLinksDetailsParam: false, - undelete: false, - versioning: false - }, - dav: { - chunking: '1.0' - }, - core: { - 'webdav-root' : environment.WEBDAV_ROOT, - status: { - edition: 'Community', - installed: 'true', - needsDbUpgrade: 'false', - versionstring: '10.0.3', - productname: 'HPI Schul-Cloud', - maintenance: 'false', - version : '10.0.3.3' - }, - pollinterval: 60 - } +app.get('/ocs/v1.php/config', (req, res, next) => { + logger.info('Requesting v1 config...') + res.send(onwcloudConfig.config) +}) + +// Maybe needs to be answered: https://doc.owncloud.com/server/admin_manual/configuration/user/user_provisioning_api.html +// returns HTML: +// '\n' + +// '\n' + +// '\n' + +// '\n' + +// 'Error\n' + +// '\n' + +// '\n' + +// '
Cannot GET /ocs/v1.php/cloud/user
\n' + +// '\n' + +// '\n', +app.get('/ocs/v1.php/cloud/user', (req, res, next) => { + logger.info('Requesting v1 user (JSON)...') + next() + /*res.send({ + ocs: { + meta: { + statuscode: 100, + status: 'ok' + }, + data: { + users: [ + 'Frank' + ] } } - } -} - -app.get('/ocs/v1.php/cloud/capabilities?format=json', (req, res) => { - logger.info('Requesting v1 capabilities (JSON)...') - res.send(capabilities) + }) + */ }) -// Seems to get requested much earlier, however, nextcloud tries to get /remote.php/webdav -app.get('/ocs/v2.php/cloud/capabilities?format=json', (req, res) => { - logger.info('Requesting v2 capabilities (JSON)...') - res.send(capabilities) +// Also returns 404 HTML-Document +app.get('/remote.php/dav/avatars/lehrer@schul-cloud.org/128.png', (req, res, next) => { + logger.info('Requesting avatar..') + next() }) // HEAD Request to webdav root maybe needs to be processed, doesn't work until now -app.head('/remote.php/webdav/', (req, res, next) => { - logger.info('Requesting HEAD of root...') - res.send() +// seems to be like some kind of "status-requests", simply responding with a 200 is sufficcient for now. +app.head('/remote.php/webdav//', (req, res, next) => { + res.send('') }) +/* +Process: + +Calling PROPFIND /remote.php/dav/files/lehrer@schul-cloud.org/ --> new URL: /remote.php/dav/files/lehrer@schul-cloud.org/ - Number: 8 +/remote.php/webdav/ +Calling PROPFIND /remote.php/dav/files/lehrer@schul-cloud.org/ --> new URL: /remote.php/webdav/ - Number: 9 + */ +//app.propfind('/remote.php/dav/files/lehrer@schul-cloud.org/',(req, res, next) => { + //console.log(req.body) + //console.log(Object.keys(req.body)) + //Console.log(req.body['d:propfind']['d:prop']) + //req.body['d:propfind']['d:prop'].array.forEach(element => { + // console.log(JSON.stringify(element)) + //}); + //const oldUrl = req.url + //const urlParts = oldUrl.split('/') + //const path = urlParts.slice(5) + //req.url = '/remote.php/webdav/'+ path.join('/') + //logger.error(req.url) + //return app._router.handle(req,res,next) +//}) + +// PROPFIND Request to /remote.php/webdav/ returns weird xml: +// http://localhost:1900/remote.php/webdav/HTTP/1.1 200 OKHTTP/1.1 404 Not Found' + +function logReqRes(req, res, next) { + const oldWrite = res.write; + const oldEnd = res.end; + + const chunks = []; + + res.write = (...restArgs) => { + chunks.push(Buffer.from(restArgs[0])); + oldWrite.apply(res, restArgs); + }; + + res.end = (...restArgs) => { + if (restArgs[0]) { + chunks.push(Buffer.from(restArgs[0])); + } + const body = Buffer.concat(chunks).toString('utf8'); + logger.warn({ + number: req.counter, + time: new Date().toUTCString(), + fromIP: req.headers['x-forwarded-for'] || + req.connection.remoteAddress, + method: req.method, + originalUri: req.originalUrl, + laterUri: req.url, + uri: req.url, + requestData: JSON.stringify(req.body), + responseData: body, + referer: req.headers.referer || '', + ua: req.headers['user-agent'], + contentType: res.get('content-type') + }); + // console.log(body); + oldEnd.apply(res, restArgs); + }; + next(); + } +app.use(logReqRes) + // root path doesn't seem to work that easily with all webdav clients, if it doesn't work simply put an empty string there app.use(webdav.extensions.express(environment.WEBDAV_ROOT, server)) +app.use(webdav.extensions.express(environment.WEBDAV_ROOT+'/', server)) +app.use(webdav.extensions.express('/remote.php/dav/files/lehrer@schul-cloud.org', server)) app.listen(environment.PORT, () => { logger.info('Ready on port ' + environment.PORT) diff --git a/package-lock.json b/package-lock.json index ae24cd3..0991ab8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,18 +5,18 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { "@babel/highlight": "^7.10.4" } }, "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", "dev": true }, "@babel/highlight": { @@ -80,28 +80,28 @@ } }, "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.3", + "@nodelib/fs.stat": "2.0.4", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.3", + "@nodelib/fs.scandir": "2.1.4", "fastq": "^1.6.0" } }, @@ -188,13 +188,13 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.9.1.tgz", - "integrity": "sha512-QRLDSvIPeI1pz5tVuurD+cStNR4sle4avtHhxA+2uyixWGFjKzJ+EaFVRW6dA/jOgjV5DTAjOxboQkRDE8cRlQ==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.11.1.tgz", + "integrity": "sha512-fABclAX2QIEDmTMk6Yd7Muv1CzFLwWM4505nETzRHpP3br6jfahD9UUJkhnJ/g2m7lwfz8IlswcwGGPGiq9exw==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.9.1", - "@typescript-eslint/scope-manager": "4.9.1", + "@typescript-eslint/experimental-utils": "4.11.1", + "@typescript-eslint/scope-manager": "4.11.1", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", @@ -203,55 +203,55 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.9.1.tgz", - "integrity": "sha512-c3k/xJqk0exLFs+cWSJxIjqLYwdHCuLWhnpnikmPQD2+NGAx9KjLYlBDcSI81EArh9FDYSL6dslAUSwILeWOxg==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.11.1.tgz", + "integrity": "sha512-mAlWowT4A6h0TC9F+J5pdbEhjNiEMO+kqPKQ4sc3fVieKL71dEqfkKgtcFVSX3cjSBwYwhImaQ/mXQF0oaI38g==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.9.1", - "@typescript-eslint/types": "4.9.1", - "@typescript-eslint/typescript-estree": "4.9.1", + "@typescript-eslint/scope-manager": "4.11.1", + "@typescript-eslint/types": "4.11.1", + "@typescript-eslint/typescript-estree": "4.11.1", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.9.1.tgz", - "integrity": "sha512-Gv2VpqiomvQ2v4UL+dXlQcZ8zCX4eTkoIW+1aGVWT6yTO+6jbxsw7yQl2z2pPl/4B9qa5JXeIbhJpONKjXIy3g==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.11.1.tgz", + "integrity": "sha512-BJ3jwPQu1jeynJ5BrjLuGfK/UJu6uwHxJ/di7sanqmUmxzmyIcd3vz58PMR7wpi8k3iWq2Q11KMYgZbUpRoIPw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.9.1", - "@typescript-eslint/types": "4.9.1", - "@typescript-eslint/typescript-estree": "4.9.1", + "@typescript-eslint/scope-manager": "4.11.1", + "@typescript-eslint/types": "4.11.1", + "@typescript-eslint/typescript-estree": "4.11.1", "debug": "^4.1.1" } }, "@typescript-eslint/scope-manager": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.9.1.tgz", - "integrity": "sha512-sa4L9yUfD/1sg9Kl8OxPxvpUcqxKXRjBeZxBuZSSV1v13hjfEJkn84n0An2hN8oLQ1PmEl2uA6FkI07idXeFgQ==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.11.1.tgz", + "integrity": "sha512-Al2P394dx+kXCl61fhrrZ1FTI7qsRDIUiVSuN6rTwss6lUn8uVO2+nnF4AvO0ug8vMsy3ShkbxLu/uWZdTtJMQ==", "dev": true, "requires": { - "@typescript-eslint/types": "4.9.1", - "@typescript-eslint/visitor-keys": "4.9.1" + "@typescript-eslint/types": "4.11.1", + "@typescript-eslint/visitor-keys": "4.11.1" } }, "@typescript-eslint/types": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.9.1.tgz", - "integrity": "sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.11.1.tgz", + "integrity": "sha512-5kvd38wZpqGY4yP/6W3qhYX6Hz0NwUbijVsX2rxczpY6OXaMxh0+5E5uLJKVFwaBM7PJe1wnMym85NfKYIh6CA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.9.1.tgz", - "integrity": "sha512-bzP8vqwX6Vgmvs81bPtCkLtM/Skh36NE6unu6tsDeU/ZFoYthlTXbBmpIrvosgiDKlWTfb2ZpPELHH89aQjeQw==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.11.1.tgz", + "integrity": "sha512-tC7MKZIMRTYxQhrVAFoJq/DlRwv1bnqA4/S2r3+HuHibqvbrPcyf858lNzU7bFmy4mLeIHFYr34ar/1KumwyRw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.9.1", - "@typescript-eslint/visitor-keys": "4.9.1", + "@typescript-eslint/types": "4.11.1", + "@typescript-eslint/visitor-keys": "4.11.1", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", @@ -261,12 +261,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.1.tgz", - "integrity": "sha512-9gspzc6UqLQHd7lXQS7oWs+hrYggspv/rk6zzEMhCbYwPE/sF7oxo7GAjkS35Tdlt7wguIG+ViWCPtVZHz/ybQ==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.1.tgz", + "integrity": "sha512-IrlBhD9bm4bdYcS8xpWarazkKXlE7iYb1HzRuyBP114mIaj5DJPo11Us1HgH60dTt41TCZXMaTCAW+OILIYPOg==", "dev": true, "requires": { - "@typescript-eslint/types": "4.9.1", + "@typescript-eslint/types": "4.11.1", "eslint-visitor-keys": "^2.0.0" } }, @@ -345,9 +345,9 @@ "dev": true }, "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, "async": { @@ -356,9 +356,9 @@ "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" }, "axios": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz", - "integrity": "sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", "requires": { "follow-redirects": "^1.10.0" } @@ -638,9 +638,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "enabled": { @@ -674,9 +674,9 @@ "dev": true }, "eslint": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.15.0.tgz", - "integrity": "sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz", + "integrity": "sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -713,7 +713,7 @@ "semver": "^7.2.1", "strip-ansi": "^6.0.0", "strip-json-comments": "^3.1.0", - "table": "^5.2.3", + "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -935,9 +935,9 @@ "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" }, "fastq": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", - "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.0.tgz", + "integrity": "sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -1017,9 +1017,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "follow-redirects": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", - "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", + "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==" }, "forwarded": { "version": "0.1.2", @@ -1129,9 +1129,9 @@ "dev": true }, "import-fresh": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", - "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -1176,9 +1176,9 @@ "dev": true }, "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "is-glob": { @@ -1646,14 +1646,40 @@ "dev": true }, "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } } }, "sprintf-js": { @@ -1673,31 +1699,14 @@ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" } }, "string_decoder": { @@ -1733,15 +1742,15 @@ } }, "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/table/-/table-6.0.4.tgz", + "integrity": "sha512-sBT4xRLdALd+NFBvwOz8bw4b15htyythha+q+DVZqy2RS08PPC8O2sZFgJYEY7bJvbCFKccs+WIZ/cd+xxTWCw==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "ajv": "^6.12.4", + "lodash": "^4.17.20", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0" } }, "text-hex": { @@ -1814,9 +1823,9 @@ } }, "typescript": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz", - "integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", "dev": true }, "unpipe": { diff --git a/package.json b/package.json index 4051d2a..0243a3e 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "lint": "eslint . --ext .ts" }, "dependencies": { - "axios": "^0.21.0", + "axios": "^0.21.1", "dotenv": "^8.2.0", "express": "^4.17.1", "mime-types": "^2.1.27", @@ -16,9 +16,9 @@ }, "devDependencies": { "@types/express": "^4.17.9", - "@typescript-eslint/eslint-plugin": "^4.9.1", - "@typescript-eslint/parser": "^4.9.1", - "eslint": "^7.15.0", - "typescript": "^4.1.2" + "@typescript-eslint/eslint-plugin": "^4.11.1", + "@typescript-eslint/parser": "^4.11.1", + "eslint": "^7.16.0", + "typescript": "^4.1.3" } }