Resource::Wrangler
This module provides a very simple wrapper to handle the
scenario where you need to have a path that points to a
resource bundled in your Raku distribution.
Usage
You are creating a new Raku module and you want to be able
to provide users access to a resource that you ship in your
distribution via a file handle.
Normally this requires manual juggling of %?RESOURCES
to
get the contents of a file and to then write them to a
location manually.
With Resource::Wrangler
, it becomes simple to get either
a randomized path location (for a bit of security, where
it matters) or to copy the resource to a specific path.
The major "trick" that is required for it to work, however,
is that your consuming module needs to pass it's own resource
map as a role parameter to Resource::Wrangler
.
Most often it will look like this:
my $wrangler = Resource::Wrangler[{ %?RESOURCES }].new
But you can also create your own map (Str
=> IO
). In fact,
that's how the tests are implemented.
Randomized Path Location
The following code will copy the resource from the location
deep within %?RESOURCES
to a location based on randomized
path components (under $*TMPDIR
):
use Resource::Wrangler;
constant WR = Resource::Wrangler[{ %?RESOURCES }].new;
my IO::Path $path = WR.load-resource-to-path("resource-name.png");
say $path.Str
# >>> "/tmp/j0gbX6hUQjh20Qqf5BxAyVsanRLkDMVE/KAHsTx9m7pkE0jhMbdBdj63bp1Rjd7PI"
Note that filename
and prefix
are both available.
By default they are set to a random sequence but they can
be manually stated.
However, note that if a prefix
is passed that already exists as
a path, it will randomly add additional sub-paths from random
sequences until a non-existing prefix
path is accomplished.
For direct control over the exact resource destination, see
below.
Manual Path Location
If you prefer loading resources to persistent (outside
of $*TMPDIR
, etc) or predictable / human-readable paths, then
you can provide your own value for the filename
(it defaults to the resource name if unspecified).
The prefix
and manual
named parameters are required:
use Resource::Wrangler;
my $wr = Resource::Wrangler[{ %?RESOURCES }].new;
my IO::Path $path = $wr.load-resource-to-path(
"resource-name.png",
filename => "output-name.png",
prefix => $*HOME.add("known/safe/path"),
:manual);
say $path.Str;
# >>> "/home/user1/known/safe/path/output-name.png"
prefix
can be any value that coerces to IO()
, so the above
could have been written:
prefix => "/home/user1/known/safe/path"
Security Notes
There must always be some tension between security and usability.
It is possible that attackers can exploit any deterministic resource
naming scheme to allow arbitrary loading of malicious stuffs.
That said, software needs to remain usable to be of any benefit to
actual users, not to mention the developer experience trying to
provide software to those users.
This library uses path randomization under OS-provided temporary
directories to provide some obfuscation. Highly motivated attackers
have compromised much more complex systems than this.
That said, the original point about the balance between security
and usability still stands. If you have any concerns or have spotted
a glaring hole in the implementation of this module, please file
a ticket on the GitHub repository and it will be resolved
as soon as possible.
Please use responsibly.
License
Release under the Artistic License 2.0