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

Image Uploads #287

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open

Image Uploads #287

wants to merge 26 commits into from

Conversation

atomdmac
Copy link

@atomdmac atomdmac commented Nov 18, 2023

Description

Drag images (JPG, GIF or PNG) onto the canvas to add them to the whiteboard. Images are saved to disk into a directory with the name name as the board JSON file.

Notable Code Changes

  • Use new class BoardDataList instead of plain JS object for boards in sockets module.
    • Provides access to the boards list via functions which allows for better access control and observability. This is desirable now that multiple objects may attempt to mutate the data.
  • Add new dependency multiparty for parsing FormData on server.

TODO

  • Delete images when removed from the board
  • Support clicking on canvas with image tool to add image
  • Delete tmp file after uploading image
  • Address possible security issue here
  • When serving board image assets, don't block handler function

Future Improvements

  • Display upload progress indicator for image
  • Support for "Download Image"

@atomdmac atomdmac marked this pull request as ready for review November 18, 2023 19:06
Adam Macumber added 2 commits November 18, 2023 14:11
For empty boards, the canvas area is sometimes smaller than the
available browser window.  We want to be able to drop the image anywhere
on the screen.
@lovasoa
Copy link
Owner

lovasoa commented Nov 18, 2023

Thank you very much for contributing this long-requested feature !

I'll try to review it soon, but before:

  • can we add tests ? This is a sensitive feature with big security implications, I think it needs tests.
  • the image upload endpoint needs to be disabled when the image tool is disabled (using BLOCKED_TOOLS)

@lovasoa lovasoa marked this pull request as draft November 18, 2023 19:21
@lovasoa
Copy link
Owner

lovasoa commented Nov 18, 2023

I see there are also still TODOs in the code. Feel free to switch it back to ready for review when you are ready for me to have a look

server/server.js Outdated
break;
case "board-assets":
const [, boardId, assetName] = parts;
const file = fs.readFileSync(path.join(config.HISTORY_DIR, `board-${boardId}`, assetName));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, we cannot have blocking code like this in the request handling function

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do some more research on this but do you happen to know if calling a function that returns a promise would solve this issue?

Something like this:

async function readFile(request, response) {
  // ... create promise, read file from disk, and handle response.
}

function handleRequest(request, response) {
  // ... handlers
  case 'board-assets':
     serveFile(request, response);
     break;
  // ... other handlers
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can look at how it's done in the rest on the code; we use async fs functions

function createImageElement(data) {
var img = svg.getElementById(data.id) || Tools.createSVGElement("image");
img.setAttribute("id", data.id);
img.setAttribute("href", data.src);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a big security vulnerability, isn't it ?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyone can send an image event with the src attribute they want

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the concern that a user of Board A would be able to load images from Board B (which may be a "private" board)?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bigger concern is that they may have all users make requests to their own server

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah OK - so the concern is that an attacker could inject a URL that points to a server that they control, and that serves files with malicious content. Is that right?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they could serve whatever they want, but also log the ip addresses of everyone connected

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this has been addressed with the latest commit 👍 Let me know if you disagree.

@@ -80,7 +89,7 @@
function createImageElement(data) {
var img = svg.getElementById(data.id) || Tools.createSVGElement("image");
img.setAttribute("id", data.id);
img.setAttribute("href", data.src);
img.setAttribute("href", getAbsoluteImageUrl(data.src));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is complicated. Can we remove the src altogether ?

Suggested change
img.setAttribute("href", getAbsoluteImageUrl(data.src));
img.setAttribute("href", "./images/" + data.id);

that would stress me less :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would the browser know where to pull the image to display from?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The browser would make a request to boards/{boardname}/images/{image_id}, the server would check that the image exists, and if so, serve it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yours is a much better approach 😅 This has been updated.

@atomdmac atomdmac marked this pull request as ready for review November 21, 2023 15:21
@atomdmac
Copy link
Author

Progress update: I've added some tests but for some reason I can't get them to pass in FireFox (though they pass fine in Chromium).

@lovasoa
Copy link
Owner

lovasoa commented Nov 27, 2023

Great to see progress ! I don't have a lot of time to spend on wbo at the moment, but I'm determined to merge this once we are confident it works, is secure and maintainable !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants