Skip to content
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
3 changes: 3 additions & 0 deletions .github/workflows/javascript.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,6 @@ jobs:
- name: "Check '@ckeditor/ckeditor5-inspector'"
run: |
diff -wu wcfsetup/install/files/js/3rdParty/ckeditor/ckeditor5-inspector/inspector.js node_modules/@ckeditor/ckeditor5-inspector/build/inspector.js
- name: "Check 'hash-wasm'"
run: |
diff -wu wcfsetup/install/files/js/3rdParty/hash-wasm/sha256.umd.min.js node_modules/hash-wasm/dist/sha256.umd.min.js
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@woltlab/visual-dom-diff": "git+https://github.com/WoltLab/visual-dom-diff.git#e5b51fce3157d1eda310566fc1f86101341d1fea",
"@woltlab/zxcvbn": "git+https://github.com/WoltLab/zxcvbn.git#5b582b24e437f1883ccad3c37dae7c3c5f1e7da3",
"focus-trap": "^7.6.5",
"hash-wasm": "^4.12.0",
"html-parsed-element": "^0.4.1",
"perfect-scrollbar": "^1.5.6",
"qr-creator": "^1.0.0",
Expand Down
29 changes: 19 additions & 10 deletions ts/WoltLabSuite/Core/Component/File/Upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ImageResizer from "WoltLabSuite/Core/Image/Resizer";
import { AttachmentData } from "../Ckeditor/Attachment";
import { innerError } from "WoltLabSuite/Core/Dom/Util";
import { getPhrase } from "WoltLabSuite/Core/Language";
import { createSHA256 } from "hash-wasm";

export type CkeditorDropEvent = {
file: File;
Expand All @@ -36,6 +37,8 @@ type ResizeConfiguration = {
quality: number;
};

const BUFFER_SIZE = 10 * 1_024 * 1_024;

async function upload(
element: WoltlabCoreFileUploadElement,
file: File,
Expand Down Expand Up @@ -74,7 +77,7 @@ async function upload(
const end = start + chunkSize;
const chunk = file.slice(start, end);

const checksum = await getSha256Hash(await chunk.arrayBuffer());
const checksum = await getSha256Hash(chunk);

const response = await uploadChunk(identifier, i, checksum, chunk);
if (!response.ok) {
Expand Down Expand Up @@ -119,12 +122,20 @@ async function chunkUploadCompleted(fileElement: WoltlabCoreFileElement, result:
}
}

async function getSha256Hash(data: BufferSource): Promise<string> {
const buffer = await window.crypto.subtle.digest("SHA-256", data);
async function getSha256Hash(data: Blob): Promise<string> {
const sha256 = await createSHA256();
sha256.init();

let offset = 0;

while (offset < data.size) {
const chunk = data.slice(offset, offset + BUFFER_SIZE);
const buffer = await chunk.arrayBuffer();
sha256.update(new Uint8Array(buffer));
offset += BUFFER_SIZE;
}

return Array.from(new Uint8Array(buffer))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
return sha256.digest("hex");
}

export function clearPreviousErrors(element: WoltlabCoreFileUploadElement): void {
Expand Down Expand Up @@ -312,9 +323,7 @@ export function setup(): void {
}
}

const checksums = await Promise.allSettled(
validFiles.map((file) => file.arrayBuffer().then((buffer) => getSha256Hash(buffer))),
);
const checksums = await Promise.allSettled(validFiles.map((file) => getSha256Hash(file)));

for (let i = 0, length = checksums.length; i < length; i++) {
const result = checksums[i];
Expand Down Expand Up @@ -354,7 +363,7 @@ export function setup(): void {

void resizeImage(element, file).then(async (resizeFile) => {
try {
const checksum = await getSha256Hash(await resizeFile.arrayBuffer());
const checksum = await getSha256Hash(resizeFile);
const data = await upload(element, resizeFile, checksum);
if (data === undefined || typeof data.data.attachmentID !== "number") {
promiseReject();
Expand Down
4 changes: 4 additions & 0 deletions ts/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,8 @@ declare global {
"woltlab-core-google-maps": WoltlabCoreGoogleMapsElement;
"woltlab-core-reaction-summary": WoltlabCoreReactionSummaryElement;
}

// The type `Buffer` does not exist. To avoid having to load `@types/node`, we define it here.
// @see https://github.com/Daninet/hash-wasm/issues/68
type Buffer = BufferSource;
}

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions wcfsetup/install/files/js/require.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ requirejs.config({
"@woltlab/editor": "3rdParty/ckeditor/ckeditor5.bundle",
"ckeditor5-translation": "3rdParty/ckeditor/translations",
"diff-match-patch": "3rdParty/diff-match-patch/diff_match_patch.min",
"hash-wasm": "3rdParty/hash-wasm/sha256.umd.min",
},
packages: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
final class FileProcessor extends SingletonFactory
{
public const MAXIMUM_NUMBER_OF_CHUNKS = 255;
public const MAXIMUM_CHUNK_SIZE = 99_000_000;

/**
* @var array<string, ObjectType>
Expand Down Expand Up @@ -361,11 +362,13 @@ public function getOptimalChunkSize(): int
{
$postMaxSize = \ini_parse_quantity(\ini_get('post_max_size'));
if ($postMaxSize === 0) {
// Disabling it is fishy, assume a more reasonable limit of 100 MB.
$postMaxSize = 100_000_000;
// Disabling it is fishy, assume a more reasonable limit of 99 MB.
return self::MAXIMUM_CHUNK_SIZE;
}

return $postMaxSize;
// 99 MB is a reasonable upper limit that also plays nice with services
// like Cloudflare that usually come with a 100 MB request limit.
return \min(self::MAXIMUM_CHUNK_SIZE, $postMaxSize);
}

public function getMaximumFileSize(): int
Expand Down