lib/localhost/authority.rb in localhost-1.2.0 vs lib/localhost/authority.rb in localhost-1.3.0
- old
+ new
@@ -1,22 +1,26 @@
# frozen_string_literal: true
# Released under the MIT License.
-# Copyright, 2018-2023, by Samuel Williams.
+# Copyright, 2018-2024, by Samuel Williams.
# Copyright, 2019, by Richard S. Leung.
# Copyright, 2021, by Akshay Birajdar.
# Copyright, 2021, by Ye Lin Aung.
# Copyright, 2023, by Antonio Terceiro.
# Copyright, 2023, by Yuuji Yaginuma.
+# Copyright, 2024, by Colin Shea.
+require 'fileutils'
require 'openssl'
module Localhost
# Represents a single public/private key pair for a given hostname.
class Authority
+ # Where to store the key pair on the filesystem. This is a subdirectory
+ # of $XDG_STATE_HOME, or ~/.local/state/ when that's not defined.
def self.path
- File.expand_path("~/.localhost")
+ File.expand_path("localhost.rb", ENV.fetch("XDG_STATE_HOME", "~/.local/state"))
end
# List all certificate authorities in the given directory:
def self.list(root = self.path)
return to_enum(:list) unless block_given?
@@ -174,31 +178,31 @@
)
end
end
def load(path = @root)
- if File.directory?(path)
- certificate_path = File.join(path, "#{@hostname}.crt")
- key_path = File.join(path, "#{@hostname}.key")
-
- return false unless File.exist?(certificate_path) and File.exist?(key_path)
-
- certificate = OpenSSL::X509::Certificate.new(File.read(certificate_path))
- key = OpenSSL::PKey::RSA.new(File.read(key_path))
-
- # Certificates with old version need to be regenerated.
- return false if certificate.version < 2
-
- @certificate = certificate
- @key = key
-
- return true
- end
+ ensure_authority_path_exists(path)
+
+ certificate_path = File.join(path, "#{@hostname}.crt")
+ key_path = File.join(path, "#{@hostname}.key")
+
+ return false unless File.exist?(certificate_path) and File.exist?(key_path)
+
+ certificate = OpenSSL::X509::Certificate.new(File.read(certificate_path))
+ key = OpenSSL::PKey::RSA.new(File.read(key_path))
+
+ # Certificates with old version need to be regenerated.
+ return false if certificate.version < 2
+
+ @certificate = certificate
+ @key = key
+
+ return true
end
def save(path = @root)
- Dir.mkdir(path, 0700) unless File.directory?(path)
+ ensure_authority_path_exists(path)
lockfile_path = File.join(path, "#{@hostname}.lock")
File.open(lockfile_path, File::RDWR|File::CREAT, 0644) do |lockfile|
lockfile.flock(File::LOCK_EX)
@@ -210,9 +214,23 @@
File.write(
File.join(path, "#{@hostname}.key"),
self.key.to_pem
)
+ end
+ end
+
+ # Ensures that the directory to store the certificate exists. If the legacy
+ # directory (~/.localhost/) exists, it is moved into the new XDG Basedir
+ # compliant directory.
+ def ensure_authority_path_exists(path = @root)
+ old_root = File.expand_path("~/.localhost")
+
+ if File.directory?(old_root) and not File.directory?(path)
+ # Migrates the legacy dir ~/.localhost/ to the XDG compliant directory
+ File.rename(old_root, path)
+ elsif not File.directory?(path)
+ FileUtils.makedirs(path, mode: 0700)
end
end
end
end