Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Activate express-session middlewares for all sockets in SocketIoService #8981

Merged
merged 7 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions apps/app/src/server/crowi/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import PageOperationService from '../service/page-operation';
import PassportService from '../service/passport';
import SearchService from '../service/search';
import { SlackIntegrationService } from '../service/slack-integration';
import { SocketIoService } from '../service/socket-io';
import UserGroupService from '../service/user-group';
import { UserNotificationService } from '../service/user-notification';
import { initializeYjsService } from '../service/yjs';
Expand Down Expand Up @@ -301,10 +302,7 @@ Crowi.prototype.setupS2sMessagingService = async function() {
};

Crowi.prototype.setupSocketIoService = async function() {
const SocketIoService = require('../service/socket-io');
if (this.socketIoService == null) {
this.socketIoService = new SocketIoService(this);
}
this.socketIoService = new SocketIoService(this);
};

Crowi.prototype.setupModels = async function() {
Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/server/service/config-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class ConfigManagerImpl implements ConfigManager, S2sMessageHandlable {
}
}

async removeConfigsInTheSameNamespace(namespace, configKeys: string[], withoutPublishingS2sMessage?) {
async removeConfigsInTheSameNamespace(namespace, configKeys: readonly string[], withoutPublishingS2sMessage?) {
const queries: any[] = [];
for (const key of configKeys) {
queries.push({
Expand Down
51 changes: 28 additions & 23 deletions apps/app/src/server/service/file-uploader/aws.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { ReadStream } from 'fs';

import type { GetObjectCommandInput, HeadObjectCommandInput } from '@aws-sdk/client-s3';
import {
S3Client,
Expand Down Expand Up @@ -142,6 +144,32 @@ class AwsFileUploader extends AbstractFileUploader {
: ResponseMode.REDIRECT;
}

/**
* @inheritdoc
*/
override async uploadAttachment(readStream: ReadStream, attachment: IAttachmentDocument): Promise<void> {
if (!this.getIsUploadable()) {
throw new Error('AWS is not configured.');
}

logger.debug(`File uploading: fileName=${attachment.fileName}`);

const s3 = S3Factory();

const filePath = getFilePathOnStorage(attachment);
const contentHeaders = new ContentHeaders(attachment);

await s3.send(new PutObjectCommand({
Bucket: getS3Bucket(),
Key: filePath,
Body: readStream,
ACL: getS3PutObjectCannedAcl(),
// put type and the file name for reference information when uploading
ContentType: contentHeaders.contentType?.value.toString(),
ContentDisposition: contentHeaders.contentDisposition?.value.toString(),
}));
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -280,29 +308,6 @@ module.exports = (crowi) => {
return s3.send(new DeleteObjectCommand(params));
};

(lib as any).uploadAttachment = async function(fileStream, attachment) {
if (!lib.getIsUploadable()) {
throw new Error('AWS is not configured.');
}

logger.debug(`File uploading: fileName=${attachment.fileName}`);

const s3 = S3Factory();

const filePath = getFilePathOnStorage(attachment);
const contentHeaders = new ContentHeaders(attachment);

return s3.send(new PutObjectCommand({
Bucket: getS3Bucket(),
Key: filePath,
Body: fileStream,
ACL: getS3PutObjectCannedAcl(),
// put type and the file name for reference information when uploading
ContentType: contentHeaders.contentType?.value.toString(),
ContentDisposition: contentHeaders.contentDisposition?.value.toString(),
}));
};

lib.saveFile = async function({ filePath, contentType, data }) {
const s3 = S3Factory();

Expand Down
56 changes: 32 additions & 24 deletions apps/app/src/server/service/file-uploader/azure.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { ClientSecretCredential, TokenCredential } from '@azure/identity';
import {
generateBlobSASQueryParameters,
BlobServiceClient,
import type { ReadStream } from 'fs';

import type { TokenCredential } from '@azure/identity';
import { ClientSecretCredential } from '@azure/identity';
import type {
BlobClient,
BlockBlobClient,
BlobDeleteOptions,
ContainerClient,
} from '@azure/storage-blob';
import {
generateBlobSASQueryParameters,
BlobServiceClient,
ContainerSASPermissions,
SASProtocol,
type BlobDeleteIfExistsResponse,
Expand Down Expand Up @@ -94,6 +99,29 @@ class AzureFileUploader extends AbstractFileUploader {
throw new Error('Method not implemented.');
}

/**
* @inheritdoc
*/
override async uploadAttachment(readStream: ReadStream, attachment: IAttachmentDocument): Promise<void> {
if (!this.getIsUploadable()) {
throw new Error('Azure is not configured.');
}

logger.debug(`File uploading: fileName=${attachment.fileName}`);
const filePath = getFilePathOnStorage(attachment);
const containerClient = await getContainerClient();
const blockBlobClient: BlockBlobClient = containerClient.getBlockBlobClient(filePath);
const contentHeaders = new ContentHeaders(attachment);

await blockBlobClient.uploadStream(readStream, undefined, undefined, {
blobHTTPHeaders: {
// put type and the file name for reference information when uploading
blobContentType: contentHeaders.contentType?.value.toString(),
blobContentDisposition: contentHeaders.contentDisposition?.value.toString(),
},
});
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -218,26 +246,6 @@ module.exports = (crowi) => {
}
};

(lib as any).uploadAttachment = async function(readStream, attachment) {
if (!lib.getIsUploadable()) {
throw new Error('Azure is not configured.');
}

logger.debug(`File uploading: fileName=${attachment.fileName}`);
const filePath = getFilePathOnStorage(attachment);
const containerClient = await getContainerClient();
const blockBlobClient: BlockBlobClient = containerClient.getBlockBlobClient(filePath);
const contentHeaders = new ContentHeaders(attachment);

return blockBlobClient.uploadStream(readStream, undefined, undefined, {
blobHTTPHeaders: {
// put type and the file name for reference information when uploading
blobContentType: contentHeaders.contentType?.value.toString(),
blobContentDisposition: contentHeaders.contentDisposition?.value.toString(),
},
});
};

lib.saveFile = async function({ filePath, contentType, data }) {
const containerClient = await getContainerClient();
const blockBlobClient: BlockBlobClient = containerClient.getBlockBlobClient(filePath);
Expand Down
4 changes: 4 additions & 0 deletions apps/app/src/server/service/file-uploader/file-uploader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { randomUUID } from 'crypto';
import type { ReadStream } from 'fs';

import type { Response } from 'express';

Expand Down Expand Up @@ -36,6 +37,7 @@ export interface FileUploader {
getTotalFileSize(): Promise<number>,
doCheckLimit(uploadFileSize: number, maxFileSize: number, totalLimit: number): Promise<ICheckLimitResult>,
determineResponseMode(): ResponseMode,
uploadAttachment(readStream: ReadStream, attachment: IAttachmentDocument): Promise<void>,
respond(res: Response, attachment: IAttachmentDocument, opts?: RespondOptions): void,
findDeliveryFile(attachment: IAttachmentDocument): Promise<NodeJS.ReadableStream>,
generateTemporaryUrl(attachment: IAttachmentDocument, opts?: RespondOptions): Promise<TemporaryUrl>,
Expand Down Expand Up @@ -151,6 +153,8 @@ export abstract class AbstractFileUploader implements FileUploader {
return ResponseMode.RELAY;
}

abstract uploadAttachment(readStream: ReadStream, attachment: IAttachmentDocument): Promise<void>;

/**
* Respond to the HTTP request.
*/
Expand Down
43 changes: 24 additions & 19 deletions apps/app/src/server/service/file-uploader/gcs.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { ReadStream } from 'fs';

import { Storage } from '@google-cloud/storage';
import urljoin from 'url-join';

Expand Down Expand Up @@ -94,6 +96,28 @@ class GcsFileUploader extends AbstractFileUploader {
: ResponseMode.REDIRECT;
}

/**
* @inheritdoc
*/
override async uploadAttachment(readStream: ReadStream, attachment: IAttachmentDocument): Promise<void> {
if (!this.getIsUploadable()) {
throw new Error('GCS is not configured.');
}

logger.debug(`File uploading: fileName=${attachment.fileName}`);

const gcs = getGcsInstance();
const myBucket = gcs.bucket(getGcsBucket());
const filePath = getFilePathOnStorage(attachment);
const contentHeaders = new ContentHeaders(attachment);

await myBucket.upload(readStream.path.toString(), {
destination: filePath,
// put type and the file name for reference information when uploading
contentType: contentHeaders.contentType?.value.toString(),
});
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -201,25 +225,6 @@ module.exports = function(crowi: Crowi) {
});
};

(lib as any).uploadAttachment = function(fileStream, attachment) {
if (!lib.getIsUploadable()) {
throw new Error('GCS is not configured.');
}

logger.debug(`File uploading: fileName=${attachment.fileName}`);

const gcs = getGcsInstance();
const myBucket = gcs.bucket(getGcsBucket());
const filePath = getFilePathOnStorage(attachment);
const contentHeaders = new ContentHeaders(attachment);

return myBucket.upload(fileStream.path, {
destination: filePath,
// put type and the file name for reference information when uploading
contentType: contentHeaders.contentType?.value.toString(),
});
};

lib.saveFile = async function({ filePath, contentType, data }) {
const gcs = getGcsInstance();
const myBucket = gcs.bucket(getGcsBucket());
Expand Down
54 changes: 30 additions & 24 deletions apps/app/src/server/service/file-uploader/gridfs.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ReadStream } from 'fs';
import { Readable } from 'stream';
import util from 'util';

Expand All @@ -16,6 +17,17 @@ import { ContentHeaders } from './utils';
const logger = loggerFactory('growi:service:fileUploaderGridfs');


const COLLECTION_NAME = 'attachmentFiles';
const CHUNK_COLLECTION_NAME = `${COLLECTION_NAME}.chunks`;

// instantiate mongoose-gridfs
const AttachmentFile = createModel({
modelName: COLLECTION_NAME,
bucketName: COLLECTION_NAME,
connection: mongoose.connection,
});


// TODO: rewrite this module to be a type-safe implementation
class GridfsFileUploader extends AbstractFileUploader {

Expand Down Expand Up @@ -47,6 +59,24 @@ class GridfsFileUploader extends AbstractFileUploader {
throw new Error('Method not implemented.');
}

/**
* @inheritdoc
*/
override async uploadAttachment(readStream: ReadStream, attachment: IAttachmentDocument): Promise<void> {
logger.debug(`File uploading: fileName=${attachment.fileName}`);

const contentHeaders = new ContentHeaders(attachment);

return AttachmentFile.promisifiedWrite(
{
// put type and the file name for reference information when uploading
filename: attachment.fileName,
contentType: contentHeaders.contentType?.value.toString(),
},
readStream,
);
}

/**
* @inheritdoc
*/
Expand All @@ -73,15 +103,6 @@ class GridfsFileUploader extends AbstractFileUploader {

module.exports = function(crowi) {
const lib = new GridfsFileUploader(crowi);
const COLLECTION_NAME = 'attachmentFiles';
const CHUNK_COLLECTION_NAME = `${COLLECTION_NAME}.chunks`;

// instantiate mongoose-gridfs
const AttachmentFile = createModel({
modelName: COLLECTION_NAME,
bucketName: COLLECTION_NAME,
connection: mongoose.connection,
});

// get Collection instance of chunk
const chunkCollection = mongoose.connection.collection(CHUNK_COLLECTION_NAME);
Expand Down Expand Up @@ -150,21 +171,6 @@ module.exports = function(crowi) {
return lib.doCheckLimit(uploadFileSize, maxFileSize, totalLimit);
};

(lib as any).uploadAttachment = async function(fileStream, attachment) {
logger.debug(`File uploading: fileName=${attachment.fileName}`);

const contentHeaders = new ContentHeaders(attachment);

return AttachmentFile.promisifiedWrite(
{
// put type and the file name for reference information when uploading
filename: attachment.fileName,
contentType: contentHeaders.contentType?.value.toString(),
},
fileStream,
);
};

lib.saveFile = async function({ filePath, contentType, data }) {
const readable = new Readable();
readable.push(data);
Expand Down
10 changes: 9 additions & 1 deletion apps/app/src/server/service/file-uploader/local.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ReadStream } from 'fs';
import { Readable } from 'stream';

import type { Response } from 'express';
Expand Down Expand Up @@ -71,6 +72,13 @@ class LocalFileUploader extends AbstractFileUploader {
: ResponseMode.RELAY;
}

/**
* @inheritdoc
*/
override async uploadAttachment(readStream: ReadStream, attachment: IAttachmentDocument): Promise<void> {
throw new Error('Method not implemented.');
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -146,7 +154,7 @@ module.exports = function(crowi) {
return fs.unlinkSync(filePath);
};

(lib as any).uploadAttachment = async function(fileStream, attachment) {
lib.uploadAttachment = async function(fileStream, attachment) {
logger.debug(`File uploading: fileName=${attachment.fileName}`);

const filePath = getFilePathOnStorage(attachment);
Expand Down
Loading
Loading