Onehub allows you to organize files into Workspaces and folders, and control access by inviting people to certain items. However, many of our customers have requested additional flexibility in the way that they share their sensitive data with other people.

Imagine that as the marketing director of Coffee House Co., I would like to solicit bids for a logo redesign. Thomas from Whiz Bang Studios and Alice from Acme Design Collective are both going to be submitting bids for this job, and they both need access to the same folder containing visual assets and style guides. They also each need their own folder where they can upload their proposals, works in progress, and receive additional documents not intended for the other designer.

Since I’m the Administrator, I need to be able to see everything in the Workspace, and it would also be great to see some indication when folders are hidden by default.

As the administrator of the Workspace, all folders are visible

Thomas and Alice, on the other hand, only see their respective folders.

Thomas's view is on top, Alice's is shown below.

Notice that both Thomas and Alice see a helpful icon to alert them to the fact that they have increased privileges in their folders.

In addition to being able to hide folders after they’ve been created, we also added a switch to hide them right when they’re created, so that Creators and below won’t see any activity pertaining to the folder, until they’re given explicit access.

We’ve worked hard on these new features, and hope that you find them useful. Click here to head to our support site for more detailed information, as well as examples of some common security scenarios.

Did you like this? Share it:

The AWS::S3 library for Ruby has been around since the release of Amazon S3 in 2006; hundreds, if not thousands, of applications use it. Consequently, it is not usually “the suspect” when looking for the cause of intermittent access errors to S3. However, we recently found and fixed an error that has been present in the signature calculation method since the library was first released.

We use S3 as the backing store for Onehub Workspaces, and we do a lot of S3 operations. During routine log monitoring we noticed a slow, but persistent, stream of HTTP 403 (Unauthorized Access) errors from S3. These errors were not frequent enough to cause problems for our customers; applications using S3 should be designed anticipate errors, and retry. Still, we felt that further investigation was warranted.

To manage the logs generated by all of the Onehub services, we use Papertrail. Papertrail allows us to run a real-time search against our production logs, showing us requests to S3 like this:


https://s3.amazonaws.com/<bucket>/<object>?AWSAccessKeyId=<ouraccesskey>&Expires=1328127911&Signature=l74ewTX9hh0s2oiLoIY83V%2BlLuM%3D

The components used to calculate the signature are well documented by Amazon. When a signature fails, S3 will provide the components it attempted to use in the XML returned with the error message. We noticed that the signatures in these errors were different than those that should have been calculated for the provided Expires time. We monkey-patched the #canonical_signature method of AWS::S3::Authentication::Signature to handle a closure.

module AWS
  module S3
    class Authentication
      class Signature
        private
        def encoded_canonical
          digest = OpenSSL::Digest::Digest.new('sha1')
          b64_hmac = [OpenSSL::HMAC.digest(digest, secret_access_key, canonical_string)].pack("m").strip
          if options[:debug_proc]
            options[:debug_proc].call(sprintf("AWS::S3::Authentication::Signature - request %s encoded canonical: %s %s  canonical: [%s]", @request.path, b64_hmac, CGI.escape(b64_hmac), canonical_string))
          end
          url_encode? ? CGI.escape(b64_hmac) : b64_hmac
        end
      end
    end
  end
end

This enabled us to pass in an option to AWS::S3#url_for containing a closure with our debugging method.

options = options.merge({:debug_proc => lambda{|x| logger.warn(x)}})
the_url = AssetStore.url_for(key_name, options)

We put this through testing, and into production, then waited for the next error to appear.

AWS::S3::Authentication::Signature - request /<bucket>/<keyname> encoded canonical: l74ewTX9hh0s2oiLoIY83V+lLuM= l74ewTX9hh0s2oiLoIY83V%2BlLuM%3D canonical: [GET#012#012#0121328127912#012/<bucket>/<keyname>]

https://s3.amazonaws.com/<bucket>/<object>?AWSAccessKeyId=<OURACCESSKEY>&Expires=1328127911&Signature=l74ewTX9hh0s2oiLoIY83V%2BlLuM%3D

From here we could see the error. The Expires time used to calculate the signature was different that the time provided in the URL. The value 1328127911 is in the URL, while 1328127912 was used to calculate the signature!

But why?

It took a bit of digging through the AWS::S3 source, but we found the culprit. When generating these S3 URLs, we pass an expires_in option to AWS::S3#url_for.

# Signature is the abstract super class for the Header and QueryString authentication methods. It does the job
# of computing the canonical_string using the CanonicalString class as well as encoding the canonical string. The subclasses
# parameterize these computations and arrange them in a string form appropriate to how they are used, in one case a http request
# header value, and in the other case key/value query string parameter pairs.
class Signature < String #:nodoc:
  attr_reader :request, :access_key_id, :secret_access_key, :options

  def initialize(request, access_key_id, secret_access_key, options = {})
    super()
    @request, @access_key_id, @secret_access_key = request, access_key_id, secret_access_key
    @options = options
  end

  private

    def canonical_string
      options = {}
      options[:expires] = expires if expires?
      CanonicalString.new(request, options)
    end
    memoized :canonical_string

    def encoded_canonical
      digest   = OpenSSL::Digest::Digest.new('sha1')
      b64_hmac = [OpenSSL::HMAC.digest(digest, secret_access_key, canonical_string)].pack("m").strip
      url_encode? ? CGI.escape(b64_hmac) : b64_hmac
    end

    def url_encode?
      !@options[:url_encode].nil?
    end

    def expires?
      is_a? QueryString
    end

    def date
      request['date'].to_s.strip.empty? ? Time.now : Time.parse(request['date'])
    end
end

# Provides query string authentication by computing the three authorization parameters: AWSAccessKeyId, Expires and Signature.
# More details about the various authentication schemes can be found in the docs for its containing module, Authentication.
class QueryString < Signature #:nodoc:
  constant :DEFAULT_EXPIRY, 300 # 5 minutes
  def initialize(*args)
    super
    options[:url_encode] = true
    self << build
  end

  private

    # Will return one of three values, in the following order of precedence:
    #
    #   1) Seconds since the epoch explicitly passed in the +:expires+ option
    #   2) The current time in seconds since the epoch plus the number of seconds passed in
    #      the +:expires_in+ option
    #   3) The current time in seconds since the epoch plus the default number of seconds (60 seconds)
    def expires
      return options[:expires] if options[:expires]
      date.to_i + expires_in
    end

    def expires_in
      options.has_key?(:expires_in) ? Integer(options[:expires_in]) : DEFAULT_EXPIRY
    end

    # Keep in alphabetical order
    def build
      "AWSAccessKeyId=#{access_key_id}&Expires=#{expires}&Signature=#{encoded_canonical}"
    end
end

The #initialize method is the entry point, but most of the work is done by #build. The bug was immediately apparent once we looked at #expires. Because #build calls #expires, and then #encoded_canonical calls it later, the date used can change. The #date method uses Time.now, if these calls happened on different seconds, they would result in different values. The solution is to memoize the time; it could be done in #expires or #date.

def expires
  return options[:expires] if options[:expires]
  @expires ||= date.to_i + expires_in
end

Interestingly, this error is only possible if the expires_in option is used. We suspect most people either use the library’s DEFAULT_EXPIRY or pass in an expires option, both of which cause #expires to avoid the call to #date.

After a bit of testing we put this code into production and have eliminated these errors, resulting in better performance for our customers. We have also submitted a pull request to the library maintainer.

Did you like this? Share it:

Uploading and sharing confidential information can be scary. What if the information is leaked? How do I prevent people from downloading and distributing confidential documents? These are all important questions to consider when sharing confidential documents. Today we are announcing a new Document Watermark feature to give you more control over your information and provide a way to track documents after they are downloaded.

Document Watermarks automatically insert a Watermark with the user’s email, date and the word Confidential when a user views the document online or downloads. If a user has download permission, the user will download a protected PDF that includes the Watermark. Administrators and Moderators will still have access to the original documents.

Viewing Documents Online

When viewing documents in a Workspace with Watermarks enabled, the file preview automatically displays a watermark on every page.

Downloading Documents

When downloading documents, the user gets a protected PDF with the watermark instead of the original file. Administrators and Moderators in the Workspace can download the original file without a watermark.

Sample of downloaded document with watermark

How do I enable Watermarks?

To enable Watermarks in your Workspace, click the Settings icon in the top right next to the Workspace name. Choose the Security area, and click Enable Document Watermarks.

The Document Watermark feature is available starting today on the Team and Enterprise Edition plans. Learn more about Document Watermarks on our Help site.

Did you like this? Share it:

Onehub Workspaces uses a role-based permission system to control access to files and information. The role is set when the user is invited and can be changed at any time by an Administrator or Moderator. One of the challenges with role-based permissions, is viewing the information you are sharing as a different role. This is now easy in Workspaces with the new View Workspaces As feature.

How it Works

When sharing a Workspace, folder or file, you select the role of the user you are inviting. Next to the role drop-down are two icons, Help and View As.

Screen shot of the share interface

When you select View As, your view is replaced using the permissions of the role you selected. The top Onehub bar is replaced with a Preview Bar. To return to the normal view, click the X icon in the top right to exit preview mode.

Screen Shot of Workspace

Available Roles

Note: All roles inherit the permissions of the roles below them.

  • Administrator. Can edit the Workspace pages, modify the logo and colors, and modify the Workspace security settings.
  • Moderator. Can upload, edit and delete any file or folder. Can invite other users to the Workspace, invite users to a file and folder, create secure links, and edit all comments in the Workspace.
  • Creator. Can view previews, print, and download files. Can upload files to a folder or Workspace and delete folders and files they created. Can view and add comments to files, folders and messages. Can post Messages to a Workspace.
  • Downloader. Can view previews, print and download files. Cannot view or add comments to items.
  • Printer. Can view previews and print but cannot download files. Cannot view or add comments to items.
  • Viewer. Can view previews of files but cannot print or download files. Cannot view or add comments to items.

Have Questions? You can read more about role-based permission on the Onehub Help site.

Did you like this? Share it:

When sharing information your brand should be the focus not ours. With this in mind, we recently updated the Workspace emails to include your branding.

Onehub Workspaces sends email for several events including inviting a new users, commenting on an item, posting a new message and daily notification emails. All of these emails now include the color and logo from the Workspace.

Example of the new branded invitation emails

Examples of the new comment emails

Note: These changes only apply to users on Workspaces version 2. If you don’t see branded emails, you may be using Workspaces version 1. To learn more about migrating to Workspaces 2, please contact us at support@onehub.com.

Did you like this? Share it:

We moved! After a several month search, we leased office space in Pioneer Square. The new office is located in an awesome neighborhood that has become the tech hub of Seattle and gives us room to grow for the next few years.

If you are not familiar with Seattle, Pioneer Square is a historic neighborhood in the heart of Seattle. The neighborhood was settled in 1852 and the early buildings were wooden structures. In 1889, the Great Seattle Fire destroyed much of the neighborhood and the wooden buildings were replaced with brick and stone buildings. Our new office is in a historic brick building that was recently renovated.

Our new mailing address:

Onehub Inc.
105 S Main Street, Suite 240
Seattle, WA 98104

Map of the new office:


We are unpacking and settling in to the new space. It is a big change to move from private offices to a large open space. So far, we love it. We will post photos when we are finishing unpacking. For now, here is a quick photo from my phone.

Did you like this? Share it:

For all paid Workspaces plans, you can purchase additional storage a la carte. Additional storage is sold per GB and the price ranged from $2 – $5 per GB depending on your plan. Today, we are lowering the price for additional storage to $1 per GB on all plans.


If you have purchased additional storage already, you don’t need to do anything to get the lower price. The new price will take affect on your next billing cycle.

View the full price list for Workspaces.

Did you like this? Share it:

Today we are launching a beautifully designed, dedicated marketing site for Onehub Transfers. The goal of the site is to better engage visitors with great copy, alluring design and a super simple sign up process.

The change won’t affect the way you use Transfers but having a dedicated site will make it easier to explain each product to new visitors. The Transfers product section on onehub.com will go away soon and will be replaced with new content for the upcoming launch of Workspaces 2.

Transfers Marketing Site

Our lead designer, Matthew Anderson, did an awesome job on the site so you should take a look and let us know what you think in the comments.

Did you like this? Share it:

Today we’ve added in the ability to delete individual versions of files. You can find this in the file details under the versions tab. Just click the red X icon next to the version you would like to remove to delete it. Please note that deleting a version will permanently remove it and it will not be added to the recycle bin.

Did you like this? Share it:

Sharing files online is great. As long as you don’t have to switch to your browser every 5 minutes to manually upload and download files when they change.

Onehub Sync is a new feature for Workspaces that keeps a local copy of all the files and folders stored in the online Workspace. The Onehub Sync client is a lightweight application than runs continually to watch for changes to online and local files. When changes are detected, the client automatically synchronizes the two.

Download Onehub Sync

Why should you try Onehub Sync?

It’s Easy. Onehub Sync only takes a few minutes to setup.
It’s Automatic. Once installed, you work on files in your special Onehub folder and everything is automatically synchronized in the background.
It’s Free. Onehub Sync is free with any paid plan. For free users, you can try Sync free for 30 days.

Benefits of Onehub Sync

Increase Productivity

By seamlessly connecting your computer to the robust collaboration tools offered in Onehub Workspaces you can more productively and efficiently work with people inside and outside your firewall.

Effortless Collaboration

When other members of your workspace use Onehub sync, you’ll automatically receive their changes as well. Everyone in the workspace always has the most up-to-date versions of files.

Work Offline

Access and work on your files even when you’re offline. Any changes you make will be tracked and synced with your workspaces the next time you are online.

Learn more about Onehub Sync.

Did you like this? Share it: