As a longtime developer of rights management solutions, we have been searching for an elegant answer to the problem of sharing confidential documents within and between organizations. Existing solutions do not provide everyday business users with an easy way to prevent sharing of documents beyond a particular group, which may include members of outside organizations (e.g. a board of directors).
FileOpen has solutions in market for controlling access to documents both inside and outside the company firewall, but our “last mile” still relies on email attachments or websites to deliver encrypted files, and on logins or email “magic links” to authenticate end-users. This forces our customers (document owners) and their end-users (document viewers) to switch context in order to share encrypted documents and view them, adding friction to workflows and the end-user experience.
Until now. By integrating with Slack and Slack Connect, FileOpen Sharebot offers a user-friendly but powerful solution for enterprise document control. Slack provides the essential components of communication, identity management, and file delivery in a single familiar context – and FileOpen Sharebot adds an additional layer of file-level security and an enhanced document viewing experience. The result is a plug-and-play secure document sharing solution that empowers anyone in Slack to limit access to the Users and Channels they designate, even across different Workspaces.
FileOpen Sharebot also improves the end-user experience by seamlessly authenticating via Slack identity, with no additional password or authentication requirement. Protected documents may not be shared to other channels, downloaded, or extracted, adding a critical layer of security for documents that contain confidential or private information. With Sharebot, every Slack instance can become a secure portal, a locked-down virtual deal room, a regulation-compliant workspace, or all of these at once.
What it does
FileOpen Sharebot enables secure management and distribution of PDFs uploaded to Slack. It has two parts: an authoring App that exposes tools to control a document, giving the Owner a variety of options, and a viewer App that displays the encrypted document in the browser after querying Slack to verify the User's identity and privileges.
To the maximum extent possible, Sharebot is built to operate inside of Slack. Rather than offering Slack users document security by exporting files to a remote platform with its own identity system (e.g. Box, Dropbox, Egnyte, etc.) FileOpen Sharebot makes Slack the single-source-of-truth for both file and identity management.
Sharebot seamlessly and transparently secures distribution to external parties via Slack Connect. If and when needed, the system can also be used to distribute files from within Slack to users entirely outside of the Slack ecosystem, with persistent security.
An additional benefit is that Sharebot reduces the attack surface of a Slack instance. Because all Sharebot PDFs are strongly encrypted (PDF V5 / AES 256), use of the system effectively eliminates the risk from an attacker exfiltrating those documents.
The Sharebot system detects the upload of a PDF to Slack and prompts the user to select the Workgroup, Channel or User to which they want to grant access. Sharebot then replaces that PDF with an encrypted version that can be controlled[^1]. When a user tries to open the document the FileOpen PermissionServer logic obtains data from Slack and then evaluates the request. Permission can be granted with a variety of granular usage controls and revoked at any time. All actions are logged and every document is uniquely watermarked with user-specific values.
Sharebot links document permissions to Slack permissions. In most cases the system can be administered entirely from Slack, i.e. a User can be granted access to a document by being added to a Workgroup or Channel and access can be revoked in the same way.
Some of the Sharebot functionality is necessarily external to Slack: the process that encrypts files runs on the Sharebot server as does the database holding rules and usage data. These functions are exposed to Sharebot in the form of REST services[^2]. We intend to expose the same services, with authentication, to other developers within the Slack ecosystem, e.g. to enable the Sharebot functionality to be added to apps or workflows automating document production/storage/retrieval, or for sharing analytic data, etc.
Alternative uses of the system are also possible: Sharebot can be used to track usage without imposing strict control (e.g. getting a notification in Slack when a user opens a document)[^3].
We describe the technology in more detail below: there’s a play-by-play of the system workflow in Appendix 1 and a detailed description of the Slack API integration in Appendix 2.
How we built it
Sharebot is FileOpen's core functionality integrated, as tightly as we could make it, into Slack.
FileOpen and Slack connect in three ways:
Sharebot gets the Owner's requirements and PDF from within Slack then transparently calls the FileOpen encryption and registration system.
Sharebot Viewer gets the Reader's identity information via Sign-in-with-Slack and queries the FileOpen backend (aka "PermissionServer") to get the Owner's requirements, then opens the PDF or doesn't.
Sharebot interacts with services exposed by the FileOpen PermissionServer to get usage data and to manage document availability and permissions.
We built two apps (to limit Scope-requests for Readers) that run in a single server environment[^4]. Some code was used in both, in particular a subsystem developed to manage token rotation, but the apps are independent. They do communicate indirectly via the PermissionServer database and might in future also use Message Metadata to maintain state and/or provide additional usage information to Owners.
The system was deployed into AWS, initially as a single server and then as separate development and production servers (sharebot-dev.fileopen.com and sharebot.fileopen.com). Graphics showing system design and AWS implementation are included in the submission.
We would be pleased to provide additional detail about the FileOpen software and REST services upon request and/or to share application source code with Slack.
Challenges we ran into
This was our first interaction with the Slack API. The trail was steep at times but well marked. When we did get lost there was nearly always a tutorial or a thread on Github or Stackoverflow with helpful directions.
Along the way we ran into two types of issues:
Functionality that restricts what we want to do and/or works in ways that create UX issues.
Functionality that we understand, now, is necessary but didn't realize we'd have to implement.
The first category (apparent limitations of the Slack API)
Can't process files prior to sharing
Our app replaces an unencrypted PDF with an encrypted PDF, after asking for permission. The system works nominally if the original PDF is uploaded to the app's Home>Messages tab or the user’s own DM conversation, because only the uploading user has access to the PDF prior to encryption. In this case the app can wait for invocation. But when the PDF is uploaded to a Channel there's an issue: the app should wait for invocation, but while waiting the unencrypted PDF is exposed to the Channel and can be opened/downloaded without control.
One workaround would be to automatically capture the PDF immediately upon sharing and hold a copy while awaiting invocation; then, should the user decline, replace the unencrypted PDF[^5]. But a better approach might be to operate on the file while in the Message Composer Box but before the user has clicked the Send Now arrow, i.e. during the interval between file_created and file_shared. The app can access the file during this stage, i.e. could delete the file, but is not permitted to raise a Modal dialog until after the file has been shared.
Sign-in-with-Slack Workspace choice and persistence
A user trying to open a PDF with Sharebot Viewer must sign-in-with-Slack to provide identity information and membership of Channels etc. so that the system can check values against the rules specified by the owner.
These values are Workspace-specific so it is imperative that the user sign-in to the correct Workspace. In testing we've found cases where a user's browser has more than one Workspace open and the sign-in-with-Slack interaction presents the wrong Workspace as the default option. Users can select a different Workspace via a drop-down menu, but doing so requires more situational awareness than we can expect.
We added a "Sign Out" option to the Viewer so the user can back out and try again. Going forward we intend to present a message prior to sign-in naming the correct Workspace and also to update our error messages when access is denied for this reason. But since in every case the Workspace in which the user clicked the link is the Workspace the user must sign-in-to perhaps there is a way to force the Oauth default to that originating Workspace; but if so we haven't found it.
Secondly, once a user has signed-in-with-Slack we find that attempts to open multiple files in the same Workspace nevertheless generate new sign-in-with-Slack prompts, seemingly at random intervals. We've seen reports on the web suggesting that this is a known issue related to the multi-workspace option. We're also looking for a way to persist the sign-in at least for the duration of a token, preferably without going outside of the OAuth framework.
The second category (functionality that was explained in the documentation but we nevertheless failed to understand, at first:)
Token management and rotation
We didn't realize initially that we'd need to manage unique tokens for every user. So our early builds seemed to be functional but in fact everyone was using the same token (producing confusing/amusing results). So we developed a module to handle user/bot token management, which we need to do independently in each of our apps. We could get token rotation for free from Bolt, but only the Sharebot app is built from Bolt (the Viewer app is C#/.NET). Our token manager is a centralized service that acquires, stores, rotates, and distributes bot and user tokens from Slack via internally exposed endpoints.
Installation and Authorization
Likewise we were slow to understand the process of public distribution and the difference between Installing an app into a Workspace and individual users Authorizing the app, i.e. the need/opportunity to customize the App's Home Tab for each user. Later we found that Implementing the same thing in Enterprise Grid required additional logic. The current system supports Org-wide installation and appears to work nominally in Enterprise Grid environments, but we suspect there’s more work to be done, e.g. we haven’t tested cases where there’s a Channel shared across multiple Workspaces and the app is installed in some but not others, etc.
Accomplishments that we're proud of
Our goal with Sharebot was to create a system that feels native to Slack, and can be used without obvious interaction with any other system or vendor. An ordinary user of Sharebot, either an Owner or a Reader, has no identity other than the one provided by Slack and is never asked to log-in to any system external to Slack. Of course that user is interacting with the FileOpen Sharebot server, but only in the background. We think that security software should be invisible to legitimate users, and found in Slack the platform capabilities to make that possible.
The effort to create a deep integration also prompted us to do two things that we thought were interesting and perhaps unusual, though one isn’t yet finished:
URL structure
We wanted to make Sharebot's file-naming and locating scheme resemble Slack's, to the extent possible.
The URL to a file in Slack, for private download, has this structure:
https://files.slack.com/files-pri/T02G02M1D-F02T6J3JNLS/download/file.pdf
And the Sharebot link for the same file has this structure:
https://sharebot.fileopen.com/view/U19K56GG4-F02T6J3JNLS/file.pdf
We replace the Workspace/Team identifier with the identifier of the Owner[^6], and store the TeamID in the PermissionServer record for that file. So for any file managed by Sharebot we can derive the URL to the same file in Slack (by looking up the TeamID), or the other way around (by getting the UserID from the Slack file object).
We map our URLs to Slack's URLs because our intent is to keep all files in Slack, as discussed in the next item.
Similarly, the Sharebot PermissionServer database identifies and manages users/files/Channels/Workgroups solely by means of the associated Slack ID values. We aren’t doing this now, mostly for performance reasons, but it would be possible for Sharebot to operate without storing any external identifiers other than Slack IDs and filenames.
Virtual Remote Files
One goal of the Sharebot design is to be an integral accessory to Slack, in the sense that a Slack customer should be able to implement Sharebot without trusting any hosting entity other than Slack (and themselves).
We can enable complete control over the server for cases where the customer demands exclusivity over that resource[^7]. Such private Sharebot instances could also host encrypted files in the local environment or some other location like Box.com (we have a connector for Box;) but we think that the system is more elegant and secure if every file is stored in Slack.
Sharebot creates remote files because the native Slack viewer can’t render our encrypted PDFs. But we don’t need or want files to be remote/external. So our intent is that a remote file we create with a URL in the form shown above should be an indirect pointer to the same file hosted in Slack[^8]. That is, when the user accesses a remote file created by Sharebot the system should retrieve that PDF from Slack before decrypting and displaying it in the browser.
In other words we want to make remote files that aren't actually remote. This approach works at a technical level and we don't see why Slack would object to it, but we thought we should ask first.
What we learned
As mentioned elsewhere in this narrative, we at FileOpen have long experience with APIs: the Acrobat plug-in API, Windows, Mac and Linux native APIs, Microsoft's server and database APIs, etc. But until now we'd never integrated our whole system into a web-native API like Slack's.
FWIW as a testament to the quality of Slack's documentation and examples, we were able to develop this system with no direct help from Slack, using only the API documentation and the many discussions on the web.
We're also fairly new to OAuth. Luckily we had test instances working against Azure AD, Okta and Ping before we started this project, so adding Sign-in-with-Slack wasn't as hard for us as it otherwise might have been. But because the Sharebot Viewer app doesn't use Bolt we had to create logic for token management that would otherwise have been provided by the Slack API, so we now understand the mechanics of Slack OAuth more than we otherwise would.
What's next for FileOpen Sharebot
Our next milestone is to submit the app to slack App Directory review. Some of what remains to be done is described in our FAQ here:.
If given permission to operate within the Slack ecosystem we plan to extend the system along two axes:
By adding functionality present in the FileOpen solution but not exposed in Sharebot.
By developing additional functionality specific to Slack.
The first category (exposing existing features)
Additional Policy and Permission Options
The FileOpen platform implements a number of features that are not yet exposed by Sharebot but could be. In no particular order these include: expiration and embargo, controlled/metered printing and text extraction, control over screenshots, concurrent usage limitation, timed-access (force-closing), Offline Permission, customization of watermarks, multi-language messages, and page-level control over viewing and printing. Use of FileOpen’s desktop solution (operating in Adobe Acrobat/Reader and a few other desktop viewers) is also possible for cases where security requirements exceed what is possible in a browser.
Support for multiple files
One key feature of the FileOpen solution is control over collections of PDFs. The software can manage permissions at the Group level which enables more complex use cases than what we're showing here: e.g. granting different permissions for the same document to different users (or to the same user at different times), adding/revoking/changing permissions for collections in a single operation, encrypting multiple files at once, etc. By implementing control at the level of the collection we might enable Sharebot to become an additional document-management layer within Slack, giving users and administrators visibility into and control over potentially all of the PDFs imported into Slack.
Dynamic Encryption
FileOpen's software is used in high-volume commercial publishing environments. Some of these contain millions of PDFs. In these implementations the model demonstrated here, in which PDFs are encrypted in advance and stored in encrypted form, doesn't scale. For large collections it is necessary to move the encryption process to the point of delivery. This makes the server more complex but eliminates file-duplication and allows normal management of the collection (e.g. indexing of the files in the repository). Whether this approach will work today for Sharebot is unclear, because access to the unencrypted files must be restricted in a way that Slack does not seem to support (we’d need a way to make some PDFs in Slack inaccessible except via our process ). But it is certainly possible, i.e. we could enable every PDF in a Slack Workspace to be encrypted and viewed securely if/when the owner requests that control.
Annotation and Collaboration
Annotations in PDF are also governed by a standard and FileOpen has developed a mechanism to manage these independently of the underlying PDF. This means that we can impose security policies onto annotations corresponding to, or different from, the rules governing the documents. For example, a user might want to share annotations and comments with some but not all members of a Workspace, e.g. only with those of higher rank, or to share a document with a Channel but share comments only with a specific conversation, etc. We also think exciting possibilities could emerge from integrating PDF annotations into the Slack messaging framework itself (Chat with the author from inside the document! Let the admin send a message to everyone who has the document open right now! Archive and index the annotations separately from the documents! etc.)
The second category (Slack-specific features)
Support for EKM and Slack-specific features
Sharebot, which is to say the FileOpen PermissionServer, generates a unique key for every encrypted document. There is no requirement that keys be created by FileOpen or stored in the PermissionServer database. So integration with Slack's Enterprise Key Management scheme, i.e. AWS KMS is possible.
Similarly Sharebot could be integrated into Slack-specific functionality like information barriers, enabling selective (or partial/redacted) access to documents on the basis of those rules.
Usage Analytics and Mapping
We're aware of apps that build models of user interaction within Slack to provide visibility into organizational dynamics. These apps may not track usage and sharing of documents, but Sharebot could provide the data to support such visualization.
Inter-Application Communication
While Sharebot is tightly integrated into Slack, by design, it also exists outside of Slack, by necessity. In some scenarios this can be an advantage, as it enables distribution of documents created inside of Slack to external environments, or the converse. For example, an organization might wish to share documents with an external party that uses neither Slack nor Slack Connect and in these cases Sharebot could enable file transport via arbitrary means (website, email, etc.) and user-identity management via the owner's SSO, via credentials issued by the FileOpen PermissionServer itself, or even by federation of Sharebot for Slack with another instance of Sharebot integrated into some other messaging system.
The last of these might present an interesting potential opportunity: the same FileOpen document could be opened simultaneously by one user in Slack and another in some other system, or on the open internet, and doing so would enable the PermissionServer to act as a de facto bridge and route messages/annotations between those two users.
Epilogue
If you've read this far we thank you for your attention! And of course we would like to thank everyone at Slack and Devpost for the opportunity to take part in this process. We'll assume that any requests for additional information will come via the Slackathon process, but we'd welcome any requests for clarification or more information sent to [email protected].
We encourage anyone at Slack to install the Sharebot app from the link provided in the submission. Alternatively, Alice and Bob from the video can add anyone interested to their Workspace (an Enterprise Grid sandbox where the app is already installed), either directly or via Slack Connect.
Footnotes:
[^1]: FileOpen has developed tools to encrypt PDFs in the manner specified by ISO 32000 (a somewhat esoteric skillset, as not all PDF objects get encrypted making it necessary to understand PDF structure and features), along with modules for client/server interaction and key management/permissioning at the client-end. We’ve long offered binary desktop client software, mostly for Acrobat/Reader, and now also have a solution to render a PDF securely in a browser.
For a security solution operating in a browser it is critically important to deliver encrypted PDF because even if the viewer UI prevents file-download a skilled user can retrieve the PDF from the browser context. FileOpen's “BrowserUX” system delivers the encrypted PDF to the browser and uses modules we developed, mostly in Rust, to handle the client/server interaction, key-exchange and file decryption.
It is worth noting that this solution does not rely upon, indeed ignores, the PDF viewer embedded in the browser, if any: we deliver our own customizable/brandable/mobile-responsive PDF viewer in real-time. This viewer exposes many more functions than the native PDF viewers in browsers or the native Slack viewer (annotation/commenting, text and page modification, digital signatures, etc.); for most purposes it is functionally equivalent to Adobe Acrobat on the desktop.
[^2]: The FileOpen PermissionServer exposes APIs for most operations, e.g. adding/removing Users from the system or moving Users in/out of Permission Groups, adding/removing Documents from Permission Groups, revoking/enabling Documents, etc.
The PermissionServer also has an API for encryption tools to register documents, because by design we provide that functionality locally (to assure chain-of-custody, i.e. not require export of unencrypted documents for encryption). But in the Sharebot app it wasn't feasible to perform client-side encryption so we developed a new Service for remote encryption. As above we’d be happy to show that Service to Slack.
[^3]: The base functionality of the system is to encrypt PDFs and allow decryption only when certain conditions are met. These conditions can have arbitrary restrictiveness, i.e. anywhere on a spectrum from allowing unidentified users to open the documents with or without tracking to, for example, only allowing a specific user to open a document on a single machine then forcibly closing it after some number of seconds and then preventing further usage. That is, Sharebot can control or can facilitate document sharing. Imposing strict control is the harder problem, so we have focused the submission on that functionality.
[^4]: Accordingly we split into two teams: "BlueTeam" to build the authoring tools and "GreenTeam" to build the viewer and back-end logic. The BlueTeam started with a prototype that had been developed to run under localhost using Ngrok and Node.js and rebuilt it using Bolt and Node. The GreenTeam started with the existing FileOpen Viewer and PermissionServer and developed code to handle token management, Sign-in-with-Slack and viewer control, mostly using C#. The BlueTeam and GreenTeam each had two developers, another developer worked with both teams on UI, still another worked on devops/AWS configuration, and one built the prototype then handled project management, explanatory writing and creation of the video.
[^5]: Going forward we expect to provide an option to automatically process every PDF uploaded to a Channel with Sharebot integration, but we don’t think this should be default behavior.
[^6]: We use the term "Owner", or sometimes "Author", to identify the person who has control over a file. The same entity is identified by Slack as the "user" who created the file. But for us the "user" is someone who accesses the Owner's document: all Owners are Users but not all Users are Owners.
[^7]: A private PermissionServer could be a separate instance and database hosted by us or an actual on-prem system. FileOpen's technical and licensing model has three options: SaaS/cloud-hosted, hybrid/private-cloud hosted, and on-premise. We think Sharebot should be a SaaS offering, but if needed the system can be operated entirely by the licensee, e.g. behind a firewall, giving FileOpen zero visibility into or control over the running instance.
[^8]: Unlike most secure file-hosting solutions, e.g. Box.com or Egnyte, which operate primarily by controlling access to file resources, the FileOpen design is insensitive to the location of files (control is imposed at time of decryption/display, irrespective of how or from where the file was delivered), so putting the encrypted files back into Slack is both possible and desirable.
Incidentally, the same abstraction applies to file locations in Slack: when we say that a file “can’t be removed from a Channel/Workgroup” we don’t mean that the remote file object, i.e. URL, can’t be copied to some other Channel/Workgroup or shared externally - these actions we can’t control - but rather that it doesn’t matter if it is copied because the PDF can only be opened by members of the designated Channel/Workgroup.
Appendix 1: Sharebot in Operation
When Sharebot has been installed into a Workspace and authorized by a user it creates user-specific Home and Messages Tabs. It can also be added to Channels. The app registers for the file_created and file_shared events and also exposes a message Shortcut to invoke processing. When invoked the app filters filetype for PDF then checks for other conditions (file was already processed by the system, etc.). When a PDF that can be processed is identified the system presents a message offering to control the file. The app also exposes a Message Shortcut that can be invoked to operate on a PDF already uploaded to Slack.
If the operator clicks the "OK, Control it" button the app presents a modal dialog with selectors for Conversations and Users. Not making a selection equates to "Workgroup". When the dialog is dismissed the app validates the input data and extracts the PDF from Slack. It then calls the FileOpen encryption service and passes the bytes of the PDF to that process along with the selected options. The encryption process takes place in memory, the PDF is never stored on the server (except when we choose to, as is currently the case with Sharebot, see “Virtual Remote Files” above).
The remote process encrypts the PDF using a randomly generated key and creates a record in the PermissionServer database containing that key and the identifiers associated with that PDF. These identifiers include the FileID and the Owner/UserID generated by Slack along with a pointer to a set of Policies governing usage. In the current implementation all documents are given a "read-only" Policy but later versions will enable more options.
Upon completion of the encryption process the Sharebot app creates a Remote file in Slack with a URL pointing to sharebot.fileopen.com and containing the identifiers for Owner and File (URL structure is discussed in "Accomplishments"). This URL does not point directly to the PDF but rather invokes a process at sharebot.fileopen.com which then retrieves the encrypted PDF from some repository location. In the current MVP implementation files are stored on the Sharebot server, but the Sharebot design expects that encrypted PDFs will be uploaded to Slack and retrieved using the associated url_private_download link.
Sharebot then shares the Remote File to the source or target location (e.g. if a Channel was selected the remote file is shared with that Channel, likewise a User) and deletes the original PDF along with messages generated during the process.
When a User clicks the Remote File object Slack launches a browser that invokes a process at sharebot.fileopen.com. This "Sharebot Viewer" is independent of the Sharebot app that created the encrypted PDF, though both have access to the same PermissionServer database. The Sharebot Viewer then attempts to obtain the identity of the end-user from Slack. In a first instance this results in a Sign-in-with-Slack interaction during which the User must allow the app to query Slack.
The Sharebot Viewer app obtains the User's basic identity and a list of Channels to which the User has access. These values are passed to the PermissionServer which compares the list to the values specified by the Owner at encryption. If a match is found then the remainder of the Permission logic is executed and a response is sent to the Viewer browser process. This response contains the decryption key for the PDF and a set of values governing usage (Print/Edit/Copy/Annotate/Save/etc.) along with user-specific values for Watermarks to be imposed on each page of the document. As noted above Sharebot documents are currently delivered with Read-only permission. All such events - whether successful or not - are fully logged by the PermissionServer.
Finally, the Viewer process sends a Slack message to the Owner reporting the event, i.e. announcing that a specific User has been allowed to view a specific document. Failed open events are not currently reported to the document Owner, though this will be added in future versions. Usage data and other controls are or will be exposed to the Owner via the app's Home tab.
The app presents a Home Tab with one button to get "whoami" information and another marked "Administration" that logs-in to the system management console (this won't be available to users of the basic SaaS offering, but provides extensive options for overall management and customization for licensed implementations; we’d be happy to demonstrate it). The Home tab also presents a list of files processed by that instance of the app. The file listing includes links to open the PDFs and for each file a button "Manage" that opens a modal dialog with the option to revoke the file (Owners always have access to their files, even if revoked, though an admin can revoke files globally). In future versions this dialog will also provide detailed usage information for that PDF.
Appendix 2: Technical Description of Sharebot App / Token Manager
Sharebot was built using the Bolt SDK for javascript. With Bolt, the app:
- listens for event subscriptions
- responds to actions
- listens and responds to slash commands
- listens and responds to shortcuts
- listens for view submissions
Entry points
Sharebot has two main entry points that will start processing a PDF file, the file_shared event and a message shortcut.
The app has another entry point for managing a file, a button in the home tab.
The entry points are described in more detail in the next sections.
file_shared event
The app uses Bolt to listen for the file_shared event. If a PDF file was shared, an ephemeral response with text and action buttons is sent to the user. The Okay, Control it. button uses the value field to store the source channel the PDF was shared in and the file id. If the user chooses to control the PDF, the button value is used in the action handler.
The app uses Bolt to listen for the Okay, Control it button press through the action id. The listener builds a modal view that allows the user to select where the file should be shared. The same data that was stored in the button value is stored in the private_metadata field. If the user submits the modal, private_metadata is used in the view submission handler.
The app uses Bolt to listen for the view submission using the modal callback id. In the view handler, the submission values are processed and the process to share a file is invoked. The following steps take place:
- Send status message to the user
- Call FileOpen Encryption service
- Delete the original file
- Create a remote encrypted PDF file
- Delete the status message
- Send message to the recipient
- Share the remote file
- Send message to the sender
Message Shortcut
The app uses Bolt to listen for a message shortcut, Control PDF, that can be used to invoke the share modal. If the shortcut is invoked for a PDF file, the app responds with the share modal and if submitted, the view submission handler described above if used.
Manage Button
The app uses Bolt to listen for the app_home_opened event and returns a dynamically generated view that contains a list of the user's ten most recently shared files. The list contains a manage button and information about the file is stored in the value field of the button. That information is used by the action handler for the button.
If the manage button is clicked, a modal dialog is created and sent to the user that allows the user to revoke or restore access to the document.
If the modal is submitted, an api call is made to the FileOpen PermissionServer to revoke or restore access.
Middleware
The app uses Bolt listener middleware when listening to events and shortcuts. Custom middleware for the file_shared event filters out events that were not triggered for a PDF file and events that were triggered by our bot.
When the Control PDF message shortcut is invoked, custom middleware is used to filter out events for messages that do not contain a PDF file or files that have already been processed. If the shortcut event doesn't match our criteria for continuing, a message is sent to a user.
Authorize Function
The app uses the authorize option in the Bolt app constructor to verify that events the app receives originated from authorized users and workspaces. The authorize function calls the token manager service to retrieve the tokens if they are available, or an error is thrown stopping the request flow.
ExpressReceiver
The Bolt app uses a custom ExpressReciever to listen for events on a custom endpoint and to add custom routes. The domain Sharebot is hosted on has other apps running on various routes and the Bolt app needed to run on sharebot.fileopen.com/api. The endpoints options of the ExpressReceiver constructor allowed us to listen for events /api/slack/events/ instead of the default /slack/events route.
After the custom receiver was created, we added a route to create an install button. The button is created dynamically and the install url is retrieved from the token manager service. If scopes are ever changed we can update the token manager service.
Slack UI
The app uses the following UI elements:
- Home Tab view
- Modal dialogs
- Messages and ephemeral messages
- Message with buttons
- Buttons
Okay, Control it button
The button is sent in response to a file_shared event and if clicked, will invoke the share modal.
Manage Button
There is one manage button for each file listed in the home tab. If the user clicks the Manage button for a file, the revoke modal is invoked.
Share Modal
The share modal contains two dropdowns, converstation_select and users_select. If one of those is selected the file is processed for the chosen recipient. If none are selected and the modal is submitted, the file is processed for the entire team.
Revoke modal
The revoke modal contains a checkbox that allows the user to revoke or restore access to the document.
Home Tab
The home tab view is generated every time it is opened. It displays a list of recent files along with the manage button. The list of files is retrieved from the FileOpen PermissionServer.
Slash Commands
The app uses Bolt to listen for slash commands. They are primarily used for development purposes, and one is used to print the app version number.
Error Handling
The event and action handlers wrap api calls in try/catch blocks and we're using Bolt to listen for uncaught errors.
FileOpen Token Manager
The Sharebot Viewer application is written in C# (.NET), which is not supported by the Bolt SDK, so we need an alternative to handle OAuth workflow and tokens.
What it does
The FileOpen OAuth Services Module allows Sharebot and other services we created for Slack to obtain the tokens required for interaction with the Slack API.
The module has three responsibilities:
- Generate a Slack OAuth Url,
- Handle Slack OAuth redirect, and
- Distribute tokens.
The initial step in the OAuth flow is to obtain an authorization from the user. The module handles this task by generating a Slack OAuth Url using the Application-specific information (ClientId, Scopes, etc).
Once the user authorizes, the module handles the Slack redirect request, which contains the access code, by making a request to https://slack.com/api/oauth.access/ with that access code to obtain an OAuth token.
Lastly, the module exposes API endpoints accessible only by Sharebot and our other services to obtain the token(s) they need.
Under the hood, there are two components to this module, API and Services.
API
The API talks to the OAuth Services (internal) as well as other services (external). It is designed to be as accessible as possible to our other services. External interfaces are REST, internal interfaces use the Google RPC framework (gRPC).
Services
The API takes a request from the outside then repackages and sends it over to the services through the specified gRPC channel. Once the request has been processed, the services respond with the result.
How we built it
The API and the services are written in C# (.NET). The two communicate using gRPC.


Log in or sign up for Devpost to join the conversation.