Skip to content

Commit

Permalink
Merge pull request #16 from andrew-grechkin/agrechkin/2.1.0
Browse files Browse the repository at this point in the history
feat: support password delegates
  • Loading branch information
andrew-grechkin authored Dec 27, 2024
2 parents fec976d + ee7b7c3 commit 4d4bc7a
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 17 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required (VERSION 3.12 FATAL_ERROR)

project (fuse3-p7zip
VERSION 2.0.0
VERSION 2.1.0
DESCRIPTION "fuse3 file system that uses the 7zip library to mount archives"
LANGUAGES CXX
)
Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ Change where application searches for 7z.so library. By default this is `/usr/li

Provide a password which will be used if archive is protected with a password.

* FUSE3_P7ZIP_PASSFILE

Provide a password file which will be used if archive is protected with a password.

If executable file is provided then its output to /dev/stdout will be used as a password.
If non-executable file is provided then its content will be used as a password.

* FUSE3_P7ZIP_FORCE_ENCODING

Some archives (especially those ones created on windows) have file names encoded in non Unicode encoding. This
Expand Down Expand Up @@ -97,6 +104,23 @@ To check the list of all available formats run `7z i` command

## Examples

### password protected archive, request password interactively (KDE password popup window)

```bash
$ fuse3-p7zip example/archive.7z /tmp/mnt --passfile=example/password-kde
```

```bash
$ export FUSE3_P7ZIP_PASSFILE=example/password-kde
$ fuse3-p7zip example/archive.7z /tmp/mnt
```

### password protected archive, fetch password from a password storage

```bash
$ fuse3-p7zip example/archive.7z /tmp/mnt --passfile=example/password-pass
```

### vifm config snippet (mount 7zip supported archive with fuse3-p7zip in vifm)

> I suggest to use [archivemount](https://github.com/cybernoid/archivemount) for all tar-based archives as a priority and
Expand Down
Binary file added example/archive.7z
Binary file not shown.
1 change: 1 addition & 0 deletions example/pass
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SECRET
3 changes: 3 additions & 0 deletions example/password-kde
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash

kdialog --password "Enter password for: $1"
5 changes: 5 additions & 0 deletions example/password-pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env bash

echo "Password for $1" >/dev/stderr

pass show 'password/from/pass'
2 changes: 2 additions & 0 deletions include/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <string>
#include <vector>

std::string chomp(const std::string& str);

std::string utf8raw(const std::wstring& wstr, const char* encoding);

std::string utf8(const wchar_t* str);
Expand Down
108 changes: 92 additions & 16 deletions src/fuse3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "string.hpp"
#include "version.hpp"

#include <array>
#include <cstring>
#include <fstream>
#include <filesystem>
Expand Down Expand Up @@ -37,7 +38,71 @@ static struct cmd_params_t {
static const fuse_opt opts_spec[] = {CMD_OPT("--password=%s", password), CMD_OPT("-p %s", password),
CMD_OPT("--passfile=%s", passfile), FUSE_OPT_END};

static std::string cmd_password;
class IPassword {
public:
virtual ~IPassword() noexcept = default;

virtual std::string get() noexcept = 0;
};

class PasswordFromString: public IPassword {
public:
PasswordFromString(const std::string& password) noexcept
: _password(password)
{}
std::string get() noexcept
{
return _password;
}

private:
std::string _password;
};

class PasswordFromFile: public IPassword {
public:
PasswordFromFile(const std::filesystem::path& path, const std::filesystem::path& arc) noexcept
: _archive(arc)
, _path(path)
{}
std::string get() noexcept
{
if (_password.empty()) {
if (access(_path.c_str(), X_OK) == 0) {
_password = chomp(exec(_path));
} else {
std::ifstream passfile(_path);
std::istreambuf_iterator it(passfile);
std::string pass(it, {});
_password = chomp(pass);
}
}
return _password;
}

private:
std::string exec(const std::filesystem::path& path)
{
std::array<char, 1024> buffer;
std::string result;
auto cmd = std::string(path.c_str()) + " '" + _archive.c_str() + "'";
std::unique_ptr<FILE, int (*)(FILE*)> pipe(popen(cmd.c_str(), "r"), pclose);
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), static_cast<int>(buffer.size()), pipe.get()) != nullptr) {
result += buffer.data();
}

return result;
}

std::filesystem::path _archive;
std::filesystem::path _path;
std::string _password;
};

static std::unique_ptr<IPassword> cmd_password = std::make_unique<PasswordFromString>(std::string());

class Fuse::Params: public fuse_cmdline_opts {
public:
Expand Down Expand Up @@ -65,20 +130,6 @@ Fuse::Params::Params(int argc, char** argv)

CheckResult(fuse_parse_cmdline(&args, this) == 0, "fuse_parse_cmdline");

if (cmd_params.password) {
cmd_password = cmd_params.password;
} else if (cmd_params.passfile) {
std::ifstream passfile(cmd_params.passfile);
std::istreambuf_iterator it(passfile);
std::string pass(it, {});
cmd_password = pass;
} else {
auto password = std::getenv("FUSE3_P7ZIP_PASSWORD");
if (password) {
cmd_password = password;
}
}

if (show_version) {
printf("%s\n", PROJECT_VERSION);
// printf("FUSE library version %s\n", fuse_pkgversion());
Expand All @@ -93,6 +144,31 @@ Fuse::Params::Params(int argc, char** argv)
fprintf(stderr, "error: no mountpoint specified\n");
exit(0);
}

auto env_password = std::getenv("FUSE3_P7ZIP_PASSWORD");
if (env_password) {
LogDebug("using FUSE3_P7ZIP_PASSWORD\n");
cmd_password.reset(new PasswordFromString(env_password));
}

if (cmd_params.password) {
LogDebug("using --password\n");
cmd_password.reset(new PasswordFromString(cmd_params.password));
}

auto env_passfile = std::getenv("FUSE3_P7ZIP_PASSFILE");
if (env_passfile && std::filesystem::exists(env_passfile) && std::filesystem::is_regular_file(env_passfile)) {
auto path = std::filesystem::absolute(std::filesystem::path(env_passfile));
LogDebug("using FUSE3_P7ZIP_PASSFILE: %s\n", path.c_str());
cmd_password.reset(new PasswordFromFile(path, cmd_params.cli_args[0]));
}

if (cmd_params.passfile && std::filesystem::exists(cmd_params.passfile) &&
std::filesystem::is_regular_file(cmd_params.passfile)) {
auto path = std::filesystem::absolute(std::filesystem::path(cmd_params.passfile));
LogDebug("using --passfile: %s\n", path.c_str());
cmd_password.reset(new PasswordFromFile(path, cmd_params.cli_args[0]));
}
}

void Fuse::Params::print_usage()
Expand Down Expand Up @@ -249,7 +325,7 @@ const std::string& Fuse::path() const

std::string Fuse::password() const
{
return cmd_password;
return cmd_password->get();
}

ssize_t Fuse::execute(sevenzip::IArchive* arc)
Expand Down
9 changes: 9 additions & 0 deletions src/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
#include <memory>
#include <iconv.h>

std::string chomp(const std::string& str)
{
auto pos = str.find_last_not_of("\n");
if (pos != std::string::npos) {
return str.substr(0, pos + 1);
}
return str;
}

std::string utf8raw(const std::wstring& wstr, const char* encoding)
{
return utf8(std::string(wstr.begin(), wstr.end()).c_str(), encoding);
Expand Down

0 comments on commit 4d4bc7a

Please sign in to comment.