WP Manifestindependent plugin directory
manifest / media / sink

Sink WP Registry grade B. Medium-severity findings · 1 findingWP RegistryMedium-severity findings · 1 findingOpen the reportB

Sync media with an AWS S3 bucket

★ 4stars
52release downloads
≈10active sites
v1.0.5latest · 6 years ago

Install

Download sink.zip From the v1.0.5 release on GitHub, Apr 11, 2020

Upload it under Plugins → Add New Plugin → Upload Plugin, then activate.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/caffeinalab/sink/releases/download/v1.0.5/sink.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.


Logo

Sink

Sync media with an AWS S3 bucket

Sink

Sync media with an AWS S3 bucket

Jump to the newest feature.

Table of Contents

About The Project

We built Sink because in our web development architecture, we containerized and split all the services. This also meant that we decoupled software from data. In the case of media files, we use usually AWS S3 and Imgix.

This plugin makes it seamless to use S3 as a storage service throught the S3's stream implementation.

How it works

The plugin uses the configuration to connect to the S3 Bucket and move media files there once uploaded. It listens to the media_upload hooks.

New feature

As of version 1.0.3. I've redesigned the settings page and added an option to manage existing media files.

This is useful in case you're adding the plugin to an existing website or project, or enable it later on when you've configured the AWS Bucket.

Here's a video demonstration of the feature.

IMAGE ALT TEXT HERE

What it does:

  1. If there are files in your local uploads directory. The plugin will not connect WordPress to AWS S3. You're given two choices.
  2. Ignore the existing files. They'll show up as missing on the media manager.
  3. Upload them to S3. From the settings menu, you can choose to transfer the files over to S3.
    1. If you move from the page, the transfer will stop, but it will begin again once you've reopened the page and transfer the remaining files.
    2. Once the transfer has finished and there aren't any more files, the plugin will connect to S3 automatically and start working seamlessly.

Dependencies

The project depends on the aws-sdk-php. It is imported in the project with composer, but to make it possible to install the plugin, it is pushed in the repository.

Getting Started

You can just clone this repository inside your wp-content/plugins folder, or download the installable zip and install it via the WordPress dashboard.

Updates

You can update Sink directly from the WordPress' dashboard, like any other plugin.

Usage

To use Sink, just install it and configure it in the settings page based on your needs.

You can also alternatively add these settings into wp-config.php

define('SINK_AWS_REGION', "eu-west-1");
define('SINK_AWS_BUCKET', "caffeina"); // bucket name
define('SINK_AWS_ACCESS_ID', "");
define('SINK_AWS_SECRET', "");
define('SINK_AWS_UPLOADS_PATH', "uploads");

define('SINK_KEEP_SITE_DOMAIN', false);
define('SINK_CDN_ENDPOINT', 'https://caffeina.imgix.net/uploads'); // mind that there's no slash

define('SINK_HTTP_PROXY_URL', "http://localhost"); // the protocol is included
define('SINK_HTTP_PROXY_PORT', "8080");
  • When SINK_KEEP_SITE_DOMAIN is set to true, the media address will keep the WordPress URL. That means that it won't work until you add some Nginx rules to proxy the requests to the CDN endpoint.

For example, if you configure S3 and you have a file that's in https://bucket.s3.eu-west-1.amazonaws.com/static/privacy_policy.html, when setting SINK_KEEP_SITE_DOMAIN to true, WordPress will return it as WP_HOME."static/privacy_policy.html"

  • SINK_CDN_ENDPOINT has priority over SINK_KEEP_SITE_DOMAIN so if set, all images will have the CDN URL.

From the example above, WordPress would now return the static file with this URL SINK_CDN_ENDPOINT."static/privacy_policy.html"

Everything is now set up. You don't need to worry about anything else.

Resizing

Images need resized and media in general needs to be distributed. It's not reasonable to have WordPress distribute media, especially if it's a huge website and needs to be scaled.

On one side, we are already saving the files to a distributed storage like S3, so now we can decide how to deliver them. Well being in the AWS ecosystem we can choose AWS CloudFront. But on the other hand, we may be using another S3 compatible service such as Minio. Also CloudFront doesn't offer image resizing. That's why we chose to use Imgix for our projects.

There are two types of image resizing though, the one that WordPress does automatically, and the one that is dynamic for the frontend website.

The WordPress generated thumbnails (resized images) will be moved to S3 automatically.

This approach isn't recommended because it creates unnecessary copies of the same file and it adds load to the server. Use a service to resize photos on the fly instead and turn off image resizing on WordPress. And then simply proxy the images from Nginx like below.

If you use the configuration below. The web server will check for the files through the URL and in the end will forward to imgix.com automatically constructing the url of the imgix bucket as the following:

-> $domain.imgix.net -> if your website domain is caffeina.com then your imgix bucket would be caffeina.com.imgix.net

Remember that the configuration accepts any domain name but the imgix bucket will only work with one so this is not ideal.

server {
  # ...
  server_name ~^(www\.)?(?<domain>.+)$;

    set $uploads_uri $uri;
    location ~ ^/.*/uploads/(.+)$ {
      rewrite ^/.*/uploads/(.+)$ /uploads/$1;
      set $uploads_uri $uri;
    }

    location ~ ^/uploads/(.+)\-([0-9]+)x([0-9]+)\.([^\.]+)$ {
      rewrite ^/uploads/(.+)\-([0-9]+)x([0-9]+)\.([^\.]+)$ /uploads/$1.$4?$args&w=$2&h=$3;
    }

    location ~ ^/uploads/(.+)\-([0-9]+)\.([^\.]+)$ {
      rewrite ^/uploads/(.+)\-([0-9]+)\.([^\.]+)$ /uploads/$1.$3?$args&w=$2;
    }

    location ~ ^/uploads/.*$ {
      try_files $uploads_uri $uri @imgix;
    }

    location @imgix {
      proxy_pass https://$domain.imgix.net;
    }

  # ...
  # WordPress configuration
}

S3 Bucket configuration

To be for this to work, you'd need two things on AWS.

  1. An IAM role with full access to the S3 bucket dedicated to the website
  2. Setting the Bucket to be publicly accessible (readable)

Here's an example on giving the bucket public access permissions. In the example below, caffeina is the bucket name.

{
    "Version": "2008-10-17",
    "Id": "http referer policy example",
    "Statement": [
        {
            "Sid": "readonly policy",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::caffeina/*"
        }
    ]
}

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

Copyright 2014-2019 Caffeina SpA under the MIT license.

Releases

6 releases. Each count is every asset in that release; expand a row for the breakdown.

Tag
Published
Assets
Downloads
v1.0.5 latest
Apr 11, 2020 6 years ago
sink.zip
26
Apr 10, 2020 6 years ago
sink.zip
4
Mar 5, 2020 6 years ago
sink.zip
5
Oct 25, 2019 6 years ago
sink.zip
5
Oct 23, 2019 7 years ago
sink.zip
5
Oct 20, 2019 7 years ago
sink.zip
7

Active-site estimate ≈10 comes from the median of recent superseded releases. Method.

B grade

Security

Sink 1.0.5 · audited by WP Registry

Medium-severity findings.

1 medium
Audited release
1.0.5
Findings
1
Worst severity
medium
Content hash
e9c5ce4e1286d5ac1fa8741a…

Findings

  • medium Nonce-less GET flips sink_ignore_existing_media and the S3 overlay

    csrf

    UI::renderOptionsPage() is the add_options_page callback (capability manage_options). On every render it reads $_REQUEST['ignore_existing_media'] and, if present, update_option('sink_ignore_existing_media', $raw) with no sanitize, no nonce, and no check_admin_referer. The settings form itself posts to options.php with settings_fields('sink_options'), but this flag is intentionally toggled by GET links in views/OptionPage.php (?ignore_existing_media=0|1). Sink::containsLocalFiles() treats the option == 1 as 'ignore leftover local media', after which isActive() becomes true and upload_dir is rewritten to s3://. A logged-in administrator who follows a cross-site link (SameSite=Lax still sends cookies on top-level GET navigation) therefore enables or disables the entire S3 media overlay without intending to. Subscriber cannot hit this page. Blast is operational (broken/missing media, new uploads leaving the local disk) rather than RCE, so this is medium, not high.

    classes/ui.php:52-58

    Recommendation

    Stop mutating options on GET. Use a POST form with check_admin_referer('sink_ignore_existing_media') (or a dedicated admin-post action), absint/sanitize the value to 0|1, and keep the manage_options gate.

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.