feat: add support for sshfs

This commit is contained in:
Glenn Y. Rolland 2023-10-24 15:53:28 +02:00
parent 002db7026b
commit 67cd9ae964
6 changed files with 117 additions and 30 deletions

View file

@ -67,7 +67,7 @@ module GX
def run() def run()
@config.load_from_file @config.load_from_file
names_display = {} of String => NamedTuple(filesystem: GoCryptFS, ansi_name: String) names_display = {} of String => NamedTuple(filesystem: Filesystem, ansi_name: String)
@config.filesystems.each do |filesystem| @config.filesystems.each do |filesystem|
result_name = filesystem.mounted? ? "#{filesystem.name} [open]" : filesystem.name result_name = filesystem.mounted? ? "#{filesystem.name} [open]" : filesystem.name
ansi_name = filesystem.mounted? ? "#{filesystem.name} [#{ "open".colorize(:green) }]" : filesystem.name ansi_name = filesystem.mounted? ? "#{filesystem.name} [#{ "open".colorize(:green) }]" : filesystem.name

View file

@ -1,5 +1,5 @@
require "./filesystems/gocryptfs" require "./filesystems"
module GX module GX
class Config class Config
@ -13,7 +13,7 @@ module GX
record AddArgs, name : String, path : String record AddArgs, name : String, path : String
record DelArgs, name : String record DelArgs, name : String
getter filesystems : Array(GoCryptFS) getter filesystems : Array(Filesystem)
getter home_dir : String getter home_dir : String
property mode : Mode property mode : Mode
property path : String property path : String
@ -28,30 +28,31 @@ module GX
@home_dir = ENV["HOME"] @home_dir = ENV["HOME"]
@mode = Mode::Run @mode = Mode::Run
@filesystems = [] of GoCryptFS @filesystems = [] of Filesystem
@path = File.join(@home_dir, ".config", DEFAULT_CONFIG_PATH) @path = File.join(@home_dir, ".config", DEFAULT_CONFIG_PATH)
@args = NoArgs @args = NoArgs
end end
def load_from_file def load_from_file
@filesystems = [] of GoCryptFS @filesystems = [] of Filesystem
if !File.exists? @path if !File.exists? @path
STDERR.puts "Error: file #{@path} does not exist!".colorize(:red) STDERR.puts "Error: file #{@path} does not exist!".colorize(:red)
exit(1) exit(1)
end end
load_vaults(@path) load_filesystems(@path)
end end
private def load_vaults(config_path : String) private def load_filesystems(config_path : String)
yaml_data = YAML.parse(File.read(config_path)) yaml_data = YAML.parse(File.read(config_path))
vaults_data = yaml_data["filesystems"].as_a vaults_data = yaml_data["filesystems"].as_a
vaults_data.each do |vault_data| vaults_data.each do |filesystem_data|
type = vault_data["type"].as_s type = filesystem_data["type"].as_s
name = vault_data["name"].as_s name = filesystem_data["name"].as_s
encrypted_path = vault_data["encrypted_path"].as_s # encrypted_path = filesystem_data["encrypted_path"].as_s
@filesystems << GoCryptFS.new(name, encrypted_path, "#{name}.Open") @filesystems << Filesystem.from_yaml(filesystem_data.to_yaml)
# @filesystems << Filesystem.new(name, encrypted_path, "#{name}.Open")
end end
end end
end end

3
src/filesystems.cr Normal file
View file

@ -0,0 +1,3 @@
require "./filesystems/gocryptfs"
require "./filesystems/filesystem"

View file

@ -0,0 +1,38 @@
require "yaml"
module GX
abstract class Filesystem
include YAML::Serializable
use_yaml_discriminator "type", {
gocryptfs: GoCryptFS,
sshfs: SshFS
}
property type : String
end
module GenericFilesystem
def unmount
system("fusermount -u #{mount_dir.shellescape}")
puts "Filesystem #{name} is now closed.".colorize(:green)
end
def mount(&block)
Dir.mkdir_p(mount_dir) unless Dir.exists?(mount_dir)
if mounted?
puts "Already mounted. Skipping.".colorize(:yellow)
return
end
yield
puts "Filesystem #{name} is now available on #{mount_dir}".colorize(:green)
end
end
end
require "./gocryptfs"
require "./sshfs"

View file

@ -1,14 +1,19 @@
require "shellwords" require "shellwords"
require "./filesystem"
module GX module GX
class GoCryptFS class GoCryptFS < Filesystem
getter name : String getter name : String = ""
getter encrypted_path : String getter encrypted_path : String = ""
getter mount_dir : String
def initialize(@name, @encrypted_path, mount_name : String) @[YAML::Field(key: "mount_dir", ignore: true)]
getter mount_dir : String = ""
include GenericFilesystem
def after_initialize()
home_dir = ENV["HOME"] || raise "Home directory not found" home_dir = ENV["HOME"] || raise "Home directory not found"
@mount_dir = File.join(home_dir, "mnt/#{mount_name}") @mount_dir = File.join(home_dir, "mnt/#{@name}")
end end
def mounted? : Bool def mounted? : Bool
@ -16,26 +21,22 @@ module GX
end end
def mount def mount
Dir.mkdir_p(mount_dir) unless Dir.exists?(mount_dir) super do
if mounted?
puts "Already mounted. Skipping.".colorize(:yellow)
else
input = STDIN input = STDIN
output = STDOUT output = STDOUT
error = STDERR error = STDERR
process = Process.new("gocryptfs", ["-idle", "15m", encrypted_path, mount_dir], input: input, output: output, error: error) process = Process.new(
"gocryptfs",
["-idle", "15m", encrypted_path, mount_dir],
input: input,
output: output,
error: error
)
unless process.wait.success? unless process.wait.success?
puts "Error mounting the vault".colorize(:red) puts "Error mounting the vault".colorize(:red)
return return
end end
puts "GoCryptFS #{name} is now available on #{mount_dir}".colorize(:green)
end end
end end
def unmount
system("fusermount -u #{mount_dir.shellescape}")
puts "GoCryptFS #{name} is now closed.".colorize(:green)
end
end end
end end

44
src/filesystems/sshfs.cr Normal file
View file

@ -0,0 +1,44 @@
require "shellwords"
require "./filesystem"
module GX
class SshFS < Filesystem
getter name : String = ""
getter remote_path : String = ""
getter remote_user : String = ""
getter remote_host : String = ""
@[YAML::Field(key: "mount_dir", ignore: true)]
getter mount_dir : String = ""
include GenericFilesystem
def after_initialize()
home_dir = ENV["HOME"] || raise "Home directory not found"
@mount_dir = File.join(home_dir, "mnt/#{@name}")
end
def mounted? : Bool
`mount`.includes?("#{remote_user}@#{remote_host}:#{remote_path} on #{mount_dir}")
end
def mount
super do
input = STDIN
output = STDOUT
error = STDERR
process = Process.new(
"sshfs",
["#{remote_user}@#{remote_host}:#{remote_path}", mount_dir],
input: input,
output: output,
error: error
)
unless process.wait.success?
puts "Error mounting the filesystem".colorize(:red)
return
end
end
end
end
end