Workspace Agreements and File Versioning Updates

We recently introduced two great new features. The ability to add an agreement before users can access your workspaces, and better controls over the number of file versions that are kept.

Workspace Agreements

We’ve had lots of requests for this feature and it’s finally here. You can now require users to accept an agreement before they can enter a workspace. This can be managed per workspace from the workspace settings under the Security section. Once enabled you will be provided with a text box that has a default agreement. You can enter your own agreement/disclaimer and it will be shown to users the first time they enter the workspace.

They will be required to click Accept before being allowed in.

This feature is a great addition for those using Onehub as a virtual data room. We hope you enjoy it.

File Versioning Changes

We’ve always allowed you to keep multiple versions of files available, but today we have implemented a change that will help you keep a handle on older versions and their storage usage.

Previously we kept unlimited versions of files. While this can be useful sometimes, it can also eat up your storage unnecessarily and be difficult to manage. We’ve added a new workspace-wide setting that lets you choose how many versions of files to keep. By default we will now keep the last 10 versions of a file.

We’ll show you how many versions will be kept in the Versions tab of a file. This will also let you delete all of the previous versions for that file with the new Delete All Versions button.

We hope you’ll find these features useful. We’ll continue working hard to make Onehub the best and easiest way to organize and share your files in the cloud.

Introducing Folder Uploads in Google Chrome

The ability to upload entire folders from the browser is an incredibly common feature request. While we have supported folder uploads via FTP, and Onehub Sync for some time now, technical limitations have prevented us from handling folder uploads through the browser. Fortunately, that situation is starting to change.

Google Chrome recently added support for folder uploads, and we wasted no time adding it to Onehub! So, if you are using the most recent version of Chrome, you can now upload entire folders to your Workspaces – directly from your browser.

Folder Upload Menu

The change is virtually seamless, as Chrome users will simply be presented with two options when clicking “Upload”. All you have to do is click “Upload a Folder”, choose the folder you want to upload, and click “Select”. The entire folder structure and all files will be uploaded through the browser.

We hope you’re as excited about this as we are, and we will continue to activate this feature in other browsers as they begin supporting it.

Onehub for iOS Version 1.3 Update

We recently introduced version 1.3 of the Onehub iOS app. This version provides some great enhancements that make accessing your secure documents on-the-go even better.

Thumbnails and Sorting

The ability to view your workspaces in thumbnail view and change the sorting has been added. To access this you can click the page curl icon which let’s you choose how to view your file listing.

curlsort

In addition, we added a shortcut for switching between thumbnail and list view. Just shake your device and the view will toggle.

thumbnails

Passcode

You can now add a passcode lock that will require you to enter a 4 digit pin before being able to access your information. This can be added from the new settings area found in the upper left of the workspace listing.

Local Storage

We have also added the ability to manage your local storage. When files are viewed on your device, we keep a local copy of them to make viewing in the future faster. You now have control over how much space is dedicated to this, and can clear it at any time. This can also be accessed from the settings area.

Other Enhancements

Some other new enhancements in this release include:

  • The ability to assign users the new Collaborator role
  • Badges to show the number of items in a folder
  • Hidden folders are now displayed in gray to users who can see them

Introducing Advanced Permissions

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.

Finding and fixing a long standing bug in the Ruby Amazon S3 Library

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.

Introducing Document Watermarks

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.

Sample Document with Watermark

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.

View Workspace As…

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.

Introducing Branded Emails

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.

An example of the new branded invitation emails.

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.

Screen Shot 2011-09-09 at 2.06.36 PM

An example 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 [email protected].

Onehub Has a New Office

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.

Office2-1

Lower Price for Additional Storage Space

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.