Browse Source

Merge branch 'develop' of git.digitaltelepresence.com:digital-telepresence/dtp-base into develop

develop
Rob Colbert 2 years ago
parent
commit
b52450a54c
  1. 2
      .env.default
  2. 3
      .vscode/launch.json
  3. 4
      app/controllers/email.js
  4. 2
      app/models/content-report.js
  5. 2
      app/services/attachment.js
  6. 10
      app/services/chat.js
  7. 5
      app/services/content-vote.js
  8. 9
      app/services/image.js
  9. 15
      app/services/minio.js
  10. 2
      app/services/sticker.js
  11. 3
      app/views/components/off-canvas.pug
  12. 5
      app/views/components/section-title.pug
  13. 3
      app/views/components/upload-progress-dialog.pug
  14. 2
      app/views/welcome/signup.pug
  15. 2
      app/workers/chat/job/chat-room-clear.js
  16. 2
      app/workers/chat/job/chat-room-delete.js
  17. 4
      app/workers/media.js
  18. 2
      app/workers/media/job/attachment-delete.js
  19. 4
      app/workers/media/job/attachment-ingest.js
  20. 2
      app/workers/media/job/sticker-delete.js
  21. 4
      app/workers/media/job/sticker-ingest.js
  22. 135
      app/workers/media/job/webpage-screenshot.js
  23. 2
      app/workers/newsletter/job/email-send.js
  24. 2
      app/workers/newsletter/job/transmit.js
  25. 4
      client/js/index.js
  26. 1
      client/js/site-app.js
  27. 12
      client/less/site/button.less
  28. 3
      client/less/site/main.less
  29. 28
      client/less/site/nav.less
  30. 3
      config/http.js
  31. 25
      config/https.js
  32. 2
      docs/samples/service.js
  33. 1
      dtp-webapp.js
  34. 14
      gulpfile.js
  35. 39
      lib/client/js/dtp-app.js
  36. 8
      lib/site-controller.js
  37. 83
      lib/site-platform.js
  38. 6
      package.json
  39. 159
      yarn.lock

2
.env.default

@ -22,7 +22,7 @@ DTP_ATTACHMENT_WORK_PATH=/tmp/yourapp/attachment-work
# Set this to "enabled" to use NVIDIA GPU acceleration. Setting this to enabled
# without a properly-configured NVIDIA GPU will cause processing jobs to fail.
#
DTP_GPU_ACCELERATION=disabled
DTP_ENABLE_GPU=disabled
#
# Host Cache configuration

3
.vscode/launch.json

@ -14,7 +14,8 @@
"program": "${workspaceFolder:dtp-core}/dtp-webapp.js",
"console": "integratedTerminal",
"env": {
"HTTP_BIND_PORT": "3000"
"HTTP_BIND_PORT": "3000",
"HTTPS_BIND_PORT": "3400"
}
},
{

4
app/controllers/email.js

@ -17,9 +17,7 @@ class EmailController extends SiteController {
async start ( ) {
const { jobQueue: jobQueueService, limiter: limiterService } = this.dtp.services;
this.emailJobQueue = jobQueueService.getJobQueue('email', {
attempts: 3
});
this.emailJobQueue = jobQueueService.getJobQueue('email', this.dtp.config.jobQueues.email);
const router = express.Router();
this.dtp.app.use('/email', router);

2
app/models/content-report.js

@ -13,7 +13,7 @@ const REPORT_CATEGORY_LIST = ['spam','violence','threat','porn','doxxing','other
const ContentReportSchema = new Schema({
created: { type: Date, default: Date.now, required: true, index: 1, expires: '30d' },
user: { type: Schema.ObjectId, required: true, index: 1, ref: 'User' },
resourceType: { type: String, enum: [ ], required: true },
resourceType: { type: String, enum: ['Comment', 'ChatMessage'], required: true },
resource: { type: Schema.ObjectId, required: true, index: 1, refPath: 'resourceType' },
status: { type: String, enum: REPORT_STATUS_LIST, required: true, index: 1 },
category: { type: String, enum: REPORT_CATEGORY_LIST, required: true },

2
app/services/attachment.js

@ -29,7 +29,7 @@ class AttachmentService extends SiteService {
},
];
this.queue = this.getJobQueue('media');
this.queue = this.getJobQueue('media', this.dtp.config.jobQueues.media);
// this.template = this.loadViewTemplate('attachment/components/attachment-standalone.pug');
}

10
app/services/chat.js

@ -31,7 +31,12 @@ class ChatService extends SiteService {
}
async start ( ) {
const { user: userService, limiter: limiterService } = this.dtp.services;
const {
jobQueue: jobQueueService,
user: userService,
limiter: limiterService,
} = this.dtp.services;
await super.start();
this.populateChatMessage = [
@ -122,7 +127,8 @@ class ChatService extends SiteService {
this.emitter = ioEmitter(this.dtp.redis);
this.queues = {
reeeper: await this.getJobQueue('reeeper'),
media: jobQueueService.getJobQueue('media', this.dtp.config.jobQueues.media),
reeeper: jobQueueService.getJobQueue('reeeper', this.dtp.config.jobQueues.reeeper),
};
}

5
app/services/content-vote.js

@ -90,6 +90,11 @@ class ContentVoteService extends SiteService {
const updatedResource = await ResourceModel.findById(resource._id).select('resourceStats');
return { message, resourceStats: updatedResource.resourceStats };
}
async removeForResource (resource) {
this.log.info('removing all votes for resource', { resourceId: resource._id });
await ContentVote.deleteMany({ resource: resource._id });
}
}
module.exports = {

9
app/services/image.js

@ -142,7 +142,14 @@ class ImageService extends SiteService {
image.metadata = outputMetadata;
try {
let chain = sharpImage.clone().resize({ width: output.width, height: output.height });
let chain = sharpImage
.clone()
.resize({
width: output.width,
height: output.height,
options: output.resizeOptions,
})
;
chain = chain[output.format](output.formatParameters);
output.filePath = path.join(imageWorkPath, `${image._id}.${output.width}x${output.height}.${output.format}`);

15
app/services/minio.js

@ -80,6 +80,21 @@ class MinioService extends SiteService {
throw error;
}
}
async statObject (bucket, key) {
try {
const stat = await this.minio.statObject(bucket, key);
return stat;
} catch (error) {
this.log.error('failed to stat MinIO object', { bucket, key, error });
throw error;
}
}
async statFile (file) {
file.stat = await this.statObject(file.bucket, file.key);
return file.stat;
}
}
module.exports = {

2
app/services/sticker.js

@ -33,7 +33,7 @@ class StickerService extends SiteService {
},
];
this.queue = this.getJobQueue('media');
this.queue = this.getJobQueue('media', this.dtp.config.jobQueues.media);
this.stickerTemplate = this.loadViewTemplate('sticker/components/sticker-standalone.pug');
}

3
app/views/components/off-canvas.pug

@ -85,6 +85,7 @@ mixin renderMenuItem (iconClass, label)
i.fas.fa-balance-scale
.uk-width-expand Privacy Policy
.uk-text-small.uk-text-muted.uk-margin-medium
.uk-text-small.uk-margin-medium
div #{pkg.name} v#{pkg.version}
div © #{moment().format('YYYY')} #{site.company}
div Made In USA 🇺🇸

5
app/views/components/section-title.pug

@ -1,5 +1,6 @@
mixin renderSectionTitle (title, barButton)
.dtp-border-bottom
mixin renderSectionTitle (title, barButton, options)
- options = Object.assign({ withBorder: true }, options);
div(class= options.withBorder ? 'dtp-border-bottom' : 'uk-margin-small')
div(uk-grid).uk-grid-small.uk-flex-middle
.uk-width-expand
h4.uk-margin-small= title

3
app/views/components/upload-progress-dialog.pug

@ -0,0 +1,3 @@
#upload-progress-dialog(hidden).uk-width-large.uk-margin-auto.uk-margin.uk-text-center
progress#upload-progress(min=0, max=100, value=0).uk-progress.uk-margin-remove
label#upload-progress-prompt.uk-form-label Upload progress

2
app/views/welcome/signup.pug

@ -1,4 +1,4 @@
extends ../layouts/focused
extends ../layouts/main
block content
section.uk-section.uk-section-default.uk-section-xsmall

2
app/workers/chat/job/chat-room-clear.js

@ -28,7 +28,7 @@ class ChatRoomClearJob extends SiteWorkerProcess {
async start ( ) {
await super.start();
this.queue = await this.getJobQueue('chat');
this.queue = await this.getJobQueue('chat', this.dtp.config.jobQueues.chat);
this.log.info('registering job processor', { queue: this.queue.name, name: 'chat-room-clear' });
this.queue.process('chat-room-clear', this.processChatRoomClear.bind(this));

2
app/workers/chat/job/chat-room-delete.js

@ -37,7 +37,7 @@ class ChatRoomDeleteJob extends SiteWorkerProcess {
async start ( ) {
await super.start();
this.queue = await this.getJobQueue('chat');
this.queue = await this.getJobQueue('chat', this.dtp.config.jobQueues.chat);
this.log.info('registering job processor', { queue: this.queue.name, name: 'chat-room-delete' });
this.queue.process('chat-room-delete', this.processChatRoomDelete.bind(this));

4
app/workers/media.js

@ -48,7 +48,7 @@ class MediaWorker extends SiteWorker {
const stickerId = mongoose.Types.ObjectId(process.argv[2]);
this.log.info('creating sticker processing job', { stickerId });
const queue = this.getJobQueue('media');
const queue = this.getJobQueue('media', this.dtp.config.jobQueues.media);
await queue.add('sticker-ingest', { stickerId });
}
@ -58,6 +58,8 @@ class MediaWorker extends SiteWorker {
await this.loadProcessor(path.join(__dirname, 'media', 'job', 'attachment-ingest.js'));
await this.loadProcessor(path.join(__dirname, 'media', 'job', 'attachment-delete.js'));
await this.loadProcessor(path.join(__dirname, 'media', 'job', 'webpage-screenshot.js'));
await this.startProcessors();
}

2
app/workers/media/job/attachment-delete.js

@ -27,7 +27,7 @@ class AttachmentDeleteJob extends SiteWorkerProcess {
async start ( ) {
await super.start();
this.queue = await this.getJobQueue('media');
this.queue = await this.getJobQueue('media', this.dtp.config.jobQueues.media);
this.log.info('registering job processor', { queue: this.queue.name, name: 'attachment-delete' });
this.queue.process('attachment-delete', 1, this.processAttachmentDelete.bind(this));

4
app/workers/media/job/attachment-ingest.js

@ -35,7 +35,7 @@ class AttachmentIngestJob extends SiteWorkerProcess {
async start ( ) {
await super.start();
this.queue = await this.getJobQueue('media');
this.queue = await this.getJobQueue('media', this.dtp.config.jobQueues.media);
this.log.info('registering job processor', { queue: this.queue.name, name: 'attachment-ingest' });
this.queue.process('attachment-ingest', 1, this.processAttachmentIngest.bind(this));
@ -211,7 +211,7 @@ class AttachmentIngestJob extends SiteWorkerProcess {
} = this.dtp.services;
const { attachment } = job.data;
const codecVideo = (process.env.DTP_GPU_ACCELERATION === 'enabled') ? 'h264_nvenc' : 'libx264';
const codecVideo = (process.env.DTP_ENABLE_GPU === 'enabled') ? 'h264_nvenc' : 'libx264';
// generate the encoded attachment
// Output height is 100 lines by [aspect] width with width and height being

2
app/workers/media/job/sticker-delete.js

@ -27,7 +27,7 @@ class StickerDeleteJob extends SiteWorkerProcess {
async start ( ) {
await super.start();
this.queue = await this.getJobQueue('media');
this.queue = await this.getJobQueue('media', this.dtp.config.jobQueues.media);
this.log.info('registering job processor', { queue: this.queue.name, name: 'sticker-ingest' });
this.queue.process('sticker-delete', 1, this.processStickerDelete.bind(this));

4
app/workers/media/job/sticker-ingest.js

@ -36,7 +36,7 @@ class StickerIngestJob extends SiteWorkerProcess {
async start ( ) {
await super.start();
this.queue = await this.getJobQueue('media');
this.queue = await this.getJobQueue('media', this.dtp.config.jobQueues.media);
this.log.info('registering job processor', { queue: this.queue.name, name: 'sticker-ingest' });
this.queue.process('sticker-ingest', 1, this.processStickerIngest.bind(this));
@ -207,7 +207,7 @@ class StickerIngestJob extends SiteWorkerProcess {
async processStickerFFMPEG (job) {
const { media: mediaService, minio: minioService } = this.dtp.services;
const codecVideo = (process.env.DTP_GPU_ACCELERATION === 'enabled') ? 'h264_nvenc' : 'libx264';
const codecVideo = (process.env.DTP_ENABLE_GPU === 'enabled') ? 'h264_nvenc' : 'libx264';
// generate the encoded sticker
// Output height is 100 lines by [aspect] width with width and height being

135
app/workers/media/job/webpage-screenshot.js

@ -0,0 +1,135 @@
// media/job/webpage-screenshot.js
// Copyright (C) 2022 DTP Technologies, LLC
// License: Apache-2.0
'use strict';
const path = require('path');
const fs = require('fs');
const mongoose = require('mongoose');
const puppeteer = require('puppeteer');
const userAgent = require('user-agent');
const { SiteWorkerProcess } = require(path.join(__dirname, '..', '..', '..', '..', 'lib', 'site-lib'));
class WebpageScreenshotJob extends SiteWorkerProcess {
static get COMPONENT ( ) {
return {
name: 'webpageScreenshotJob',
slug: 'webpage-screenshot-job',
};
}
constructor (worker) {
super(worker, WebpageScreenshotJob.COMPONENT);
}
async start ( ) {
await super.start();
const workDirectory = path.join(
process.env.DTP_IMAGE_WORK_PATH,
'webpage-screenshot',
);
await fs.promises.mkdir(workDirectory, { recursive: true });
this.log.info('starting Puppeteer browser engine');
this.browser = await puppeteer.launch();
this.queue = await this.getJobQueue('media');
this.log.info('registering job processor', { queue: this.queue.name, name: 'webpage-screenshot' });
this.queue.process('webpage-screenshot', 1, this.processWebpageScreenshot.bind(this));
}
async stop ( ) {
if (this.browser) {
this.log.info('stopping Puppeteer browser engine');
this.browser.close();
delete this.browser;
}
await super.stop();
}
/**
* Expected job data parameters: modelName, documentId, documentPath, pageUrl.
* @param {Job} job the Bull Queue job to be processed
*/
async processWebpageScreenshot (job) {
const { image: imageService } = this.dtp.services;
const { modelName, documentId, documentPath, ownerId, pageUrl } = job.data;
const model = mongoose.model(modelName);
if (!model) {
throw new Error(`Invalid model name specified for document: ${modelName}`);
}
const imageFilename = path.join(process.env.DTP_IMAGE_WORK_PATH, 'webpage-screenshot', `${documentId}.jpg`);
this.log.info('job received to capture webpage screenshot', { modelName, documentId, pageUrl });
job.data.viewport = Object.assign({
width: 720,
height: 600,
deviceScaleFactor: 1.0,
}, job.data.viewport);
try {
job.data.document = await model.findById(documentId);
if (!job.data.document) {
throw new Error(`document not found: ${modelName}:${documentId}`);
}
this.log.info('Opening web page', { modelName, documentId, pageUrl });
job.page = await this.browser.newPage();
if (!job.page) {
throw new Error('failed to create new browser page for capturing screenshot', { modelName, documentId, pageUrl });
}
await job.page.setUserAgent(userAgent.toString());
await job.page.setViewport(job.data.viewport);
await job.page.goto(pageUrl, { waitUntil: 'networkidle2' });
this.jobLog(job, 'capturing screenshot to file');
await job.page.screenshot({
path: imageFilename,
type: 'jpeg',
quality: 85,
fullPage: job.data.fullPage || false,
});
this.jobLog(job, 'uploading screenshot to storage and database');
const outFileStat = await fs.promises.stat(imageFilename);
const imageDefinition = { };
const imageFile = {
path: imageFilename,
mimetype: 'image/jpeg',
size: outFileStat.size,
};
job.data.screenshotImage = await imageService.create({ _id: ownerId }, imageDefinition, imageFile);
this.jobLog(job, 'updating document with screenshot image');
const updateOp = { $set: { } };
updateOp.$set[documentPath] = job.data.screenshotImage._id;
await model.updateOne({ _id: documentId }, updateOp);
this.jobLog(job, 'screenshot captured and processed successfully');
} catch (error) {
this.log.error('failed to process webpage screenshot', { modelName, documentId, pageUrl, error });
throw error;
} finally {
if (job.page && !job.page.isClosed()) {
this.log.info('closing browser page after capturing screenshot', { modelName, documentId, pageUrl });
await job.page.close();
delete job.page;
}
this.log.info('removing temp screenshot file', { imageFilename });
await fs.promises.rm(imageFilename, { force: true });
}
}
}
module.exports = WebpageScreenshotJob;

2
app/workers/newsletter/job/email-send.js

@ -24,7 +24,7 @@ class NewsletterEmailSendJob extends SiteWorkerProcess {
async start ( ) {
await super.start();
this.queue = await this.getJobQueue('newsletter');
this.queue = await this.getJobQueue('newsletter', this.dtp.config.jobQueues.newsletter);
this.log.info('registering job processor', { queue: this.queue.name, name: 'email-send' });
this.queue.process('email-send', this.processEmailSend.bind(this));

2
app/workers/newsletter/job/transmit.js

@ -29,7 +29,7 @@ class NewsletterTransmitJob extends SiteWorkerProcess {
async start ( ) {
await super.start();
this.queue = await this.getJobQueue('newsletter');
this.queue = await this.getJobQueue('newsletter', this.dtp.config.jobQueues.newsletter);
this.log.info('registering job processor', { queue: this.queue.name, name: 'transmit' });
this.queue.process('transmit', this.processTransmit.bind(this));

4
client/js/index.js

@ -10,7 +10,7 @@ const dtp = window. dtp = window.dtp || { };
import DtpSiteApp from './site-app.js';
import DtpWebLog from 'dtp/dtp-log.js';
import UIkit from 'uikit';
// import UIkit from 'uikit';
/**
* Monkeypatch to count characters instead of .length's code point count.
@ -32,7 +32,7 @@ window.addEventListener('load', async ( ) => {
dtp.log.info('load', 'service worker startup complete', { scope: dtp.registration.scope });
} catch (error) {
console.log('service worker startup failed', { error });
UIkit.modal.alert(`Service worker startup failed: ${error.message}`);
// UIkit.modal.alert(`Service worker startup failed: ${error.message}`);
}
}

1
client/js/site-app.js

@ -414,6 +414,7 @@ export default class DtpSiteApp extends DtpApp {
UIkit.modal.alert(`Failed to remove image: ${error.message}`);
}
}
async submitDialogForm (event, userAction) {
await this.submitForm(event, userAction);
await this.closeCurrentDialog();

12
client/less/site/button.less

@ -143,10 +143,11 @@ button.uk-button.dtp-button-danger {
background: none;
outline: none;
border: solid 2px rgb(255, 0, 0);
color: #c8c8c8;
color: @global-color;
&:hover {
background-color: rgb(255, 0, 0);
color: #ffffff;
}
}
@ -175,4 +176,13 @@ button.uk-button.dtp-button-danger {
span.count-label {
color: #e8e8e8;
}
}
button.dtp-button-dropdown {
background: none;
border: none;
outline: none;
padding: 8px 12px;
color: @global-color;
cursor: pointer;
}

3
client/less/site/main.less

@ -22,8 +22,7 @@ body {
height: 100%;
}
&[data-current-view="oauth2-authorize-dialog"],
&[data-current-view="welcome"] {
&[data-current-view="oauth2-authorize-dialog"] {
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;

28
client/less/site/nav.less

@ -2,4 +2,32 @@
display: inline-block;
width: 1.75em;
text-align: center;
}
.uk-dropdown {
border: solid 2px @global-color;
border-radius: 8px;
}
.uk-dropdown-nav > li > a {
color: @global-muted-color;
&:hover {
color: @global-color;
}
}
a[uk-slider-item].uk-icon {
background: #000000;
border: solid 2px #4a4a4a;
color: #e8e8e8;
&:hover {
border-color: #808080;
background: darken(#ff0013ff, 20%);
}
&:active {
border-color: #e8e8e8;
background: #ff0013ff;
}
}

3
config/http.js

@ -1,3 +1,6 @@
// config/http.js
// Copyright (C) 2022 DTP Technologies, LLC
// License: Apache-2.0
'use strict';

25
config/https.js

@ -0,0 +1,25 @@
// config/https.js
// Copyright (C) 2022 DTP Technologies, LLC
// License: Apache-2.0
'use strict';
if (process.env.HTTPS_ENABLE === 'enabled') {
if (!process.env.HTTPS_SSL_CRT) {
throw new Error('Must specify HTTPS_SSL_CRT in .env (HTTPS is enabled)');
}
if (!process.env.HTTPS_SSL_KEY) {
throw new Error('Must specify HTTPS_SSL_KEY in .env (HTTPS is enabled)');
}
}
module.exports = {
enabled: process.env.HTTPS_ENABLE === 'enabled',
scheme: 'https',
address: process.env.HTTPS_BIND_ADDRESS || "127.0.0.1",
port: parseInt(process.env.HTTPS_BIND_PORT || "3400", 10),
options: {
crt: process.env.HTTPS_SSL_CRT,
key: process.env.HTTPS_SSL_KEY,
},
};

2
docs/samples/service.js

@ -19,7 +19,7 @@ class SampleService extends SiteService {
async start ( ) {
await super.start();
this.queue = this.getJobQueue('sample');
this.queue = this.getJobQueue('sample', this.dtp.config.jobQueues.sample);
}
async stop ( ) {

1
dtp-webapp.js

@ -20,6 +20,7 @@ module.config = {
component: DTP_COMPONENT,
site: require(path.join(module.rootPath, 'config', 'site')),
http: require(path.join(module.rootPath, 'config', 'http')),
https: require(path.join(module.rootPath, 'config', 'https')),
};
module.log = new SiteLog(module, module.config.component);

14
gulpfile.js

@ -22,19 +22,19 @@ function util_start_browsersync ( ) {
return new Promise((resolve, reject) => {
browserSync.init({
proxy: {
target: 'http://localhost:3000',
target: 'https://dev.core.digitaltelepresence.com:3400',
ws: true,
},
host: 'localhost',
host: 'dev.core.digitaltelepresence.com',
open: 'local',
// https: {
// key: path.join(__dirname, 'ssl', 'dtp-webapp.key'),
// cert: path.join(__dirname, 'ssl', 'dtp-webapp.crt'),
// },
https: {
key: path.join(__dirname, 'ssl', 'dtp-core.key'),
cert: path.join(__dirname, 'ssl', 'dtp-core.crt'),
},
port: 3300,
cors: true,
ui: {
port: 3400,
port: 3600,
},
notify: false,
ghostMode: {

39
lib/client/js/dtp-app.js

@ -4,6 +4,8 @@
'use strict';
import { Upload } from 'upload';
import DtpLog from './dtp-log';
import DtpSocket from './dtp-socket';
import DtpDisplayEngine from './dtp-display-engine';
@ -88,8 +90,45 @@ export default class DtpApp {
return;
}
async submitFormWithProgress (event) {
event.preventDefault();
event.stopPropagation();
const formElement = event.currentTarget || event.target;
const form = new FormData(formElement);
const progressDialog = document.querySelector(formElement.getAttribute('data-progress-dialog') || '#upload-progress-dialog');
const progressBar = document.querySelector(formElement.getAttribute('data-progress-element') || 'progress#upload-progress');
const progressPrompt = document.querySelector(formElement.getAttribute('data-progress-prompt') || '#upload-progress-prompt');
const upload = new Upload({
url: formElement.getAttribute('action'),
form,
});
upload.on('progress', (progress) => {
this.log.info('submitSemitism', 'upload progress', { progress });
progressBar.value = Math.round(progress * 100.0);
});
progressDialog.removeAttribute('hidden');
const response = await upload.upload();
progressPrompt.textContent = 'Upload complete...';
this.log.info('submitSemitism', 'upload response', { response });
const json = JSON.parse(response.data);
await this.processResponseJSON(json);
return true;
}
async processResponse (response) {
const json = await response.json();
return this.processResponseJSON(json);
}
async processResponseJSON (json) {
if (!json.success) {
this.log.error('processResponse', json.message);
throw new Error(json.message);

8
lib/site-controller.js

@ -37,8 +37,12 @@ class SiteController extends SiteCommon {
}
createMulter (slug, options) {
slug = slug || 'uploads';
if (!!slug && (typeof slug === 'object')) {
options = slug;
slug = this.component.slug;
} else {
slug = slug || this.component.slug;
}
options = Object.assign({
dest: `/tmp/${this.dtp.config.site.domainKey}/${slug}/${this.component.slug}`
}, options || { });

83
lib/site-platform.js

@ -5,6 +5,7 @@
'use strict';
const path = require('path');
const fs = require('fs');
const glob = require('glob');
const express = require('express');
@ -300,8 +301,8 @@ module.exports.startWebServer = async (dtp) => {
domain: process.env.DTP_SITE_DOMAIN,
path: '/',
httpOnly: true,
secure: false,
sameSite: 'strict',
secure: process.env.HTTP_COOKIE_SECURE === 'enabled',
sameSite: process.env.HTTP_COOKIE_SAMESITE || false,
expires: SESSION_DURATION,
},
store: null,
@ -309,7 +310,6 @@ module.exports.startWebServer = async (dtp) => {
module.sessionConfig.store = sessionStore;
if (process.env.NODE_ENV === 'production') {
module.app.set('trust proxy', 1);
// module.sessionConfig.cookie.secure = true;
}
module.app.use(session(module.sessionConfig));
@ -369,21 +369,80 @@ module.exports.startWebServer = async (dtp) => {
});
});
if (process.env.HTTP_ENABLE === 'enabled') {
if (process.env.HTTP_REDIRECT_SSL === 'enabled') {
module.log.info('creating HTTP SSL redirect app');
module.redirectApp = express();
module.redirectApp.use((req, res) => {
module.log.info('redirecting to SSL', { host: req.host, url: req.url });
res.redirect(`https://${process.env.DTP_SITE_DOMAIN}${req.url}`);
});
await module.createHttpServer(dtp, module.redirectApp);
} else {
await module.createHttpServer(dtp, module.app);
}
}
if (process.env.HTTPS_ENABLE === 'enabled') {
await module.createHttpsServer(dtp, module.app);
}
// prefer to attach Socket.io to the HTTPS server and fall back to HTTP
await module.createSocketServer(dtp, module.https || module.http);
if (module.http) {
await module.startHttpServer(dtp, module.http, dtp.config.http);
}
if (module.https) {
await module.startHttpServer(dtp, module.https, dtp.config.https);
}
module.log.info(`${dtp.config.component.name} platform online`, {
http: dtp.config.http.port,
https: dtp.config.https.port,
});
};
module.createHttpServer = async (dtp, app) => {
module.log.info('creating HTTP server');
module.http = require('http').createServer(module.app);
module.http = require('http').createServer(app);
};
module.createHttpsServer = async (dtp, app) => {
const httpsOptions = {
cert: await fs.promises.readFile(
process.env.HTTPS_SSL_CRT || path.join(dtp.config.root, 'ssl', 'dtp-webapp.crt')
),
key: await fs.promises.readFile(
process.env.HTTPS_SSL_KEY || path.join(dtp.config.root, 'ssl', 'dtp-webapp.key')
),
};
module.log.info('creating HTTPS server');
module.https = require('https').createServer(httpsOptions, app);
return module.https;
};
module.startHttpServer = async (dtp, server, config) => {
return new Promise((resolve, reject) => {
module.log.info('starting HTTP server', { port: config.port, bind: config.address });
server.listen(config.port, config.address, (err) => {
if (err) {
return reject(err);
}
return resolve();
});
});
};
module.createSocketServer = async (dtp, http) => {
module.log.info('creating Socket.io server');
const { SiteIoServer } = require(path.join(__dirname, 'site-ioserver'));
module.io = new SiteIoServer(dtp);
await module.io.start(module.http);
await module.io.start(http);
module.log.info('starting HTTP server', {
port: dtp.config.http.port,
bind: dtp.config.http.address,
});
module.http.listen(dtp.config.http.port, dtp.config.http.address, ( ) => {
module.log.info(`${dtp.config.component.name} platform online`, { port: dtp.config.http.port });
});
return module.io;
};
module.exports.shutdown = async ( ) => {

6
package.json

@ -24,6 +24,7 @@
"cookie-parser": "^1.4.6",
"cron": "^1.8.2",
"cropperjs": "^1.5.12",
"diacritics": "^1.3.0",
"diskusage-ng": "^1.0.2",
"disposable-email-provider-domains": "^1.0.9",
"dotenv": "^16.0.0",
@ -45,6 +46,7 @@
"libphonenumber-js": "^1.9.49",
"marked": "^4.0.12",
"method-override": "^3.0.0",
"mime": "^3.0.0",
"minio": "^7.0.26",
"moment": "^2.29.1",
"mongoose": "^6.2.4",
@ -65,11 +67,13 @@
"picmo": "^5.4.0",
"pretty-checkbox": "^3.0.3",
"pug": "^3.0.2",
"puppeteer": "^18.0.5",
"qrcode": "^1.5.0",
"rate-limiter-flexible": "^2.3.6",
"rotating-file-stream": "^3.0.3",
"serve-favicon": "^2.5.0",
"sharp": "^0.30.2",
"shoetest": "^1.2.1",
"slug": "^5.2.0",
"socket.io": "^4.4.1",
"socket.io-emitter": "^3.2.0",
@ -81,7 +85,9 @@
"uikit": "^3.11.1",
"uniqid": "^5.4.0",
"unzalgo": "^3.0.0",
"upload": "^1.3.1",
"url-validation": "^2.1.0",
"user-agent": "^1.0.4",
"uuid": "^8.3.2",
"zxcvbn": "^4.4.2"
},

159
yarn.lock

@ -1088,6 +1088,13 @@
"@types/node" "*"
"@types/webidl-conversions" "*"
"@types/yauzl@^2.9.1":
version "2.10.0"
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599"
integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==
dependencies:
"@types/node" "*"
"@webassemblyjs/[email protected]":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
@ -2046,7 +2053,7 @@ buffer-xor@^1.0.3:
resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=
buffer@^5.5.0, buffer@^5.6.0:
buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
@ -2682,6 +2689,13 @@ cropperjs@^1.5.12:
resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.5.12.tgz#d9c0db2bfb8c0d769d51739e8f916bbc44e10f50"
integrity sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw==
[email protected]:
version "3.1.5"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
dependencies:
node-fetch "2.6.7"
cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@ -2780,6 +2794,13 @@ [email protected]:
dependencies:
ms "2.1.2"
[email protected], debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
debug@^3.2.6, debug@^3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
@ -2787,13 +2808,6 @@ debug@^3.2.6, debug@^3.2.7:
dependencies:
ms "^2.1.1"
debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
debug@~4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
@ -2954,6 +2968,16 @@ dev-ip@^1.0.1:
resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0"
integrity sha1-p2o+0YVb56ASu4rBbLgPPADcKPA=
[email protected]:
version "0.0.1036444"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1036444.tgz#a570d3cdde61527c82f9b03919847b8ac7b1c2b9"
integrity sha512-0y4f/T8H9lsESV9kKP1HDUXgHxCdniFeJh6Erq+FbdOEvp/Ydp9t8kcAAM5gOd17pMrTDlFWntoHtzzeTUWKNw==
diacritics@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/diacritics/-/diacritics-1.3.0.tgz#3efa87323ebb863e6696cebb0082d48ff3d6f7a1"
integrity sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA==
[email protected]:
version "0.2.5"
resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f"
@ -3061,6 +3085,11 @@ double-ended-queue@^2.1.0-0:
resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c"
integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=
drange@^1.0.2:
version "1.1.1"
resolved "https://registry.yarnpkg.com/drange/-/drange-1.1.1.tgz#b2aecec2aab82fcef11dbbd7b9e32b83f8f6c0b8"
integrity sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==
"dtp-jshint-reporter@ssh://[email protected]:digital-telepresence/dtp-jshint-reporter.git#master":
version "1.0.2"
resolved "ssh://[email protected]:digital-telepresence/dtp-jshint-reporter.git#68b078b75cd6d048a9bf9bdc9b30ccc2a2145c4f"
@ -3598,6 +3627,17 @@ extglob@^2.0.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
[email protected]:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
dependencies:
debug "^4.1.1"
get-stream "^5.1.0"
yauzl "^2.10.0"
optionalDependencies:
"@types/yauzl" "^2.9.1"
fancy-log@^1.3.2, fancy-log@^1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7"
@ -4404,6 +4444,14 @@ http-proxy@^1.18.1:
follow-redirects "^1.0.0"
requires-port "^1.0.0"
[email protected]:
version "5.0.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
dependencies:
agent-base "6"
debug "4"
https-proxy-agent@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
@ -5611,6 +5659,11 @@ [email protected], mime@^1.4.1:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
mime@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7"
integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==
mimic-fn@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc"
@ -5892,6 +5945,13 @@ node-fetch@2:
dependencies:
whatwg-url "^5.0.0"
[email protected]:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
dependencies:
whatwg-url "^5.0.0"
node-gyp-build@^4.2.3:
version "4.3.0"
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3"
@ -6560,6 +6620,11 @@ process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
[email protected]:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
promise@^7.0.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
@ -6575,6 +6640,11 @@ proxy-addr@~2.0.7:
forwarded "0.2.0"
ipaddr.js "1.9.1"
[email protected]:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@ -6742,6 +6812,23 @@ pupa@^2.1.1:
dependencies:
escape-goat "^2.0.0"
puppeteer@^18.0.5:
version "18.0.5"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-18.0.5.tgz#873223b17b92345182c5b5e8cfbd6f3117f1547d"
integrity sha512-s4erjxU0VtKojPvF+KvLKG6OHUPw7gO2YV1dtOsoryyCbhrs444fXb4QZqGWuTv3V/rgSCUzeixxu34g0ZkSMA==
dependencies:
cross-fetch "3.1.5"
debug "4.3.4"
devtools-protocol "0.0.1036444"
extract-zip "2.0.1"
https-proxy-agent "5.0.1"
progress "2.0.3"
proxy-from-env "1.1.0"
rimraf "3.0.2"
tar-fs "2.1.1"
unbzip2-stream "1.4.3"
ws "8.8.1"
qrcode@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b"
@ -6767,6 +6854,14 @@ [email protected]:
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
randexp@^0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.5.3.tgz#f31c2de3148b30bdeb84b7c3f59b0ebb9fec3738"
integrity sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==
dependencies:
drange "^1.0.2"
ret "^0.2.0"
random-bytes@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b"
@ -7154,6 +7249,11 @@ responselike@^1.0.2:
dependencies:
lowercase-keys "^1.0.0"
ret@^0.2.0:
version "0.2.2"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.2.2.tgz#b6861782a1f4762dce43402a71eb7a283f44573c"
integrity sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
@ -7166,6 +7266,13 @@ ret@~0.1.10:
dependencies:
glob "^7.1.3"
[email protected]:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
ripemd160@^2.0.0, ripemd160@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
@ -7459,6 +7566,13 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shoetest@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/shoetest/-/shoetest-1.2.1.tgz#9c46899890cd913458ccc7b8ca4d0b474e357b4c"
integrity sha512-Bp7oH7yWJfAig2CGrapEcNxze4qzezqJgL+iZlpnV+Mmw5OncXAF3iP6CvwSXu51tQgSHyyfLW0O+4VTVh+ekA==
dependencies:
randexp "^0.5.3"
side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
@ -8021,7 +8135,7 @@ tapable@^2.1.1, tapable@^2.2.0:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
tar-fs@^2.0.0, tar-fs@^2.1.1:
[email protected], tar-fs@^2.0.0, tar-fs@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
@ -8355,6 +8469,14 @@ unbox-primitive@^1.0.1:
has-symbols "^1.0.2"
which-boxed-primitive "^1.0.2"
[email protected]:
version "1.4.3"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7"
integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==
dependencies:
buffer "^5.2.1"
through "^2.3.8"
unc-path-regex@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
@ -8494,6 +8616,13 @@ update-notifier@^5.1.0:
semver-diff "^3.1.1"
xdg-basedir "^4.0.0"
upload@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/upload/-/upload-1.3.1.tgz#e82b34677dd2a4d4f943c3f8317930b4c4d0439f"
integrity sha512-mDG4/vZRlUFzKScx5LzyIDUDfU3eOOdO+mSfTPKSJr9xGdrsqLf5wuj18ICrahBJJzSwVuGbxZWt3TwynULESg==
dependencies:
form-data "^4.0.0"
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
@ -8523,6 +8652,11 @@ use@^3.1.0:
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
user-agent@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/user-agent/-/user-agent-1.0.4.tgz#61201431fc7e84ea4a5e1e76392f163a1539c9a4"
integrity sha512-NPTnJ89e6ttUK+Q3ZQ6aMFo4+4HAdvsb39IypyRw/bPjE/F8TjeVpB8uqFPnUCVbI6247qPryd8OLpkEYuOwWg==
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"
@ -9069,6 +9203,11 @@ write-file-atomic@^3.0.0:
signal-exit "^3.0.2"
typedarray-to-buffer "^3.1.5"
[email protected]:
version "8.8.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.1.tgz#5dbad0feb7ade8ecc99b830c1d77c913d4955ff0"
integrity sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==
ws@^8.2.3:
version "8.3.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.3.0.tgz#7185e252c8973a60d57170175ff55fdbd116070d"
@ -9224,7 +9363,7 @@ yargs@^7.1.0:
y18n "^3.2.1"
yargs-parser "^5.0.1"
"[email protected] - 2.10.0":
"[email protected] - 2.10.0", yauzl@^2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=

Loading…
Cancel
Save