With the addition in version 3 of file access and HTTP listening (you should read those blog posts first), the combination of these two features allows for serving static content, i.e., images, HTML, JavaScript, etc., from opscotch. As security is always a top priority, HTTP requests for static content are strictly controlled in several ways.
How does this work?
Both the foundational capabilities of file access and HTTP listening (have you read those yet?) are secured in multiple ways. Serving static content adds to this. (Caveat: workflow authors could hand-roll serving of static content using the above capabilities—this is highly discouraged and may be prevented in the future. This post is not about hand-rolled workflows to perform this, but a built-in capability).
"Static content" in the context of opscotch refers to when an HTTP listener is bound to content to serve. The natural thought is that content would be files on disk. Static content in opscotch CANNOT be served straight from files on the disk; i.e., even if the file super-secret.txt
is on the disk and added to the bootstrap allowFileAccess
, opscotch WILL NOT make that available as static content (see caveat above). Rather, opscotch will only serve static content from a special step type and referencing a specially packaged file (as of version 3.0.0, this is simply a zip file) that is named in the bootstrap.
First additional security measure: static content must be packaged (currently as a zip file) and named in the allowFileAccess
in the bootstrap:
Bootstrap:
{
...
"allowFileAccess" : [
{
"id" : "myStaticContent",
"directoryOrFile" : "/a/path/to/a/zipfile.zip",
"READ" : true
}
],
...
}
The second additional security measure: an HTTP listener needs to be added to the bootstrap with the serveFromPackagedAsset
property, and the packagedAssetFileId
must reference the zip file id:
Bootstrap:
{
...
"allowHttpServerAccess" : [
{
"id" : "myStaticServer",
"port" : 12345,
"serveFromPackagedAsset" : {
"packagedAssetFileId" : "myStaticContent"
}
}
],
...
}
And the third, fourth, and fifth additional security measures: only steps of type httpFile
can bind to an HTTP listener with the serveFromPackagedAsset
property, AND must declare an http
trigger referencing the listener id, AND a resultsProcessor
to map the incoming URL to a file inside the zip file:
Workflow:
{
...
"workflows" : [
{
...
"steps" : [
{
...
"trigger" : {
"http" : {
"server" : "myStaticServer",
"path" : "/static/.*",
"method" : "GET"
}
},
"resultsProcessor" : {
"processors" : [
{
"script" : "context.setProperty('path', JSON.parse(context.getBody()).path);"
}
]
}
...
}
]
...
}
]
...
}
The resultsProcessor
must set a path
property that exactly matches the path of a file inside the zip file. Refer to the HTTP listening post and take note of the request payload that is passed to the step. In the example above, the payload (body) is parsed as JSON, and the path is extracted, then set as the path
property. Opscotch will then attempt to find the record in the zip file that exactly matches that path and streams the file bytes out. If the file cannot be found inside the zip file, a 404 will be returned.