Module: Portless::Trust

Defined in:
lib/portless/trust.rb

Overview

Install / remove our CA in the OS trust store so browsers accept the per-host certs. macOS uses the login keychain (GUI/Touch-ID auth — no sudo). A ca.trusted fingerprint marker short-circuits the check. Linux/Windows land in phase 3. Mirrors portless's trustCA paths.

Class Method Summary collapse

Class Method Details

.certsObject



11
# File 'lib/portless/trust.rb', line 11

def certs = @certs ||= Certs.new

.elevateObject



77
78
79
# File 'lib/portless/trust.rb', line 77

def elevate
  Privilege.reexec_with_sudo([ "trust" ]) || raise(Error, "sudo required to trust the CA on Linux")
end

.install!Object



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/portless/trust.rb', line 18

def install!
  certs.ensure_ca!
  if Constants::MACOS
    install_macos
  elsif linux?
    install_linux
  else
    raise Error, unsupported_message
  end
  write_marker
end

.install_linuxObject

── Linux (distro anchors + update tool; needs root) ─────────────────



48
49
50
51
52
53
54
55
# File 'lib/portless/trust.rb', line 48

def install_linux
  dir, update = linux_anchor
  return elevate if !Privilege.root? && !File.writable?(dir)

  require "fileutils"
  FileUtils.cp(State.ca_cert, File.join(dir, "rb-portless.crt"))
  system(*update) || raise(Error, "failed to run #{update.first}")
end

.install_macosObject

── macOS ────────────────────────────────────────────────────────────

Raises:



42
43
44
45
# File 'lib/portless/trust.rb', line 42

def install_macos
  ok = system("security", "add-trusted-cert", "-r", "trustRoot", "-k", , State.ca_cert)
  raise Error, "failed to trust the CA via `security add-trusted-cert`" unless ok
end

.linux?Boolean

Returns:

  • (Boolean)


81
# File 'lib/portless/trust.rb', line 81

def linux? = RbConfig::CONFIG["host_os"] =~ /linux/i

.linux_anchorObject

Map the distro to its CA anchor dir + refresh command.



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/portless/trust.rb', line 65

def linux_anchor
  id = File.read("/etc/os-release")[/^ID=(\w+)/, 1] rescue nil
  case id
  when "fedora", "rhel", "centos", "rocky", "almalinux"
    [ "/etc/pki/ca-trust/source/anchors", %w[update-ca-trust] ]
  when "arch", "manjaro"
    [ "/etc/ca-certificates/trust-source/anchors", %w[update-ca-trust] ]
  else # debian/ubuntu and friends
    [ "/usr/local/share/ca-certificates", %w[update-ca-certificates] ]
  end
end

.login_keychainObject



95
96
97
98
# File 'lib/portless/trust.rb', line 95

def 
  out = `security login-keychain -d user 2>/dev/null`.strip.delete('"')
  out.empty? ? File.expand_path("~/Library/Keychains/login.keychain-db") : out
end

.marker_matches?Boolean

Returns:

  • (Boolean)


83
84
85
86
87
88
# File 'lib/portless/trust.rb', line 83

def marker_matches?
  File.exist?(State.ca_trusted_marker) &&
    File.read(State.ca_trusted_marker).strip == certs.ca_fingerprint
rescue StandardError
  false
end

.trusted?Boolean

Returns:

  • (Boolean)


13
14
15
16
# File 'lib/portless/trust.rb', line 13

def trusted?
  certs.ensure_ca!
  marker_matches?
end

.uninstall!Object



30
31
32
33
34
35
36
37
38
39
# File 'lib/portless/trust.rb', line 30

def uninstall!
  return unless File.exist?(State.ca_cert)

  if Constants::MACOS
    system("security", "remove-trusted-cert", State.ca_cert)
  elsif linux?
    uninstall_linux
  end
  File.delete(State.ca_trusted_marker) if File.exist?(State.ca_trusted_marker)
end

.uninstall_linuxObject



57
58
59
60
61
62
# File 'lib/portless/trust.rb', line 57

def uninstall_linux
  dir, update = linux_anchor
  crt = File.join(dir, "rb-portless.crt")
  File.delete(crt) if File.exist?(crt)
  system(*update)
end

.unsupported_messageObject



100
101
102
# File 'lib/portless/trust.rb', line 100

def unsupported_message
  "automatic CA trust isn't wired for this OS yet — trust #{State.ca_cert} manually (phase 3)"
end

.write_markerObject



90
91
92
93
# File 'lib/portless/trust.rb', line 90

def write_marker
  File.write(State.ca_trusted_marker, certs.ca_fingerprint)
  State.fix_ownership
end