Class: Saro::Dat::DatManager

Inherits:
Object
  • Object
show all
Defined in:
lib/saro/dat/dat_manager.rb

Defined Under Namespace

Classes: State

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeDatManager

Returns a new instance of DatManager.



18
19
20
21
# File 'lib/saro/dat/dat_manager.rb', line 18

def initialize
  @state = EMPTY_STATE
  @write_lock = Mutex.new
end

Class Method Details

._issue(cert, plain, secure) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/saro/dat/dat_manager.rb', line 132

def self._issue(cert, plain, secure)
  now = Time.now.to_i
  expire = now + cert.dat_ttl_seconds
  cid_hex = cert.cid.to_s(16)

  plain_b64 = Saro::Dat::Util.encode_base64_url_str(plain)

  encrypted_secure = cert.crypto_key.encrypt(secure)
  secure_b64 = Saro::Dat::Util.encode_base64_url_str(encrypted_secure)

  body = "#{expire}.#{cid_hex}.#{plain_b64}.#{secure_b64}"
  signature = Saro::Dat::Util.encode_base64_url_str(cert.signature_key.sign(body))

  "#{body}.#{signature}"
end

._parse(cert, dat_input) ⇒ Object

Raises:



148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/saro/dat/dat_manager.rb', line 148

def self._parse(cert, dat_input)
  dat = Saro::Dat::Dat.from_value(dat_input)
  dat.raise_if_invalid!
  raise Saro::Dat::Error.new(Saro::Dat::ErrorCode::TOKEN_EXPIRED) if dat.expired?

  unless cert.signature_key.verify(dat.body_string, dat.signature)
    raise Saro::Dat::Error.new(Saro::Dat::ErrorCode::SIG_MISMATCH)
  end

  decrypted_secure = cert.crypto_key.decrypt(dat.secure)
  Saro::Dat::DatPayload.new(dat.plain, decrypted_secure)
end

Instance Method Details

#exports(verify_only = false) ⇒ Object



71
72
73
# File 'lib/saro/dat/dat_manager.rb', line 71

def exports(verify_only = false)
  @state.certificates.map { |cert| cert.exports(verify_only) }.join("\n")
end

#import_certificates(input_certs, clear: false) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/saro/dat/dat_manager.rb', line 23

def import_certificates(input_certs, clear: false)
  return 0 if input_certs.nil? || input_certs.empty?

  seen_cids = Set.new
  input_certs.each do |cert|
    if seen_cids.include?(cert.cid)
      raise Saro::Dat::Error.new(Saro::Dat::ErrorCode::CERT_DUPLICATE_CID, "duplicate cid #{cert.cid.to_s(16)}")
    end
    seen_cids.add(cert.cid)
  end

  renew_count = 0
  @write_lock.synchronize do
    certificates = clear ? [] : @state.certificates.dup

    cids = Set.new(certificates.map(&:cid))

    input_certs.each do |cert|
      next if cids.include?(cert.cid)

      cids.add(cert.cid)
      certificates << cert
      renew_count += 1
    end

    certificates.reject!(&:expired)
    certificates.sort_by!(&:dat_issuance_end_seconds)

    issuer = certificates.reverse_each.find(&:issuable)

    by_cid = {}
    certificates.each { |cert| by_cid[cert.cid] = cert }

    @state = State.new(issuer, certificates.freeze, by_cid.freeze).freeze
  end
  renew_count
end

#imports(format_str, clear: false) ⇒ Object



61
62
63
64
65
66
67
68
69
# File 'lib/saro/dat/dat_manager.rb', line 61

def imports(format_str, clear: false)
  certs = []
  format_str.strip.split("\n").each do |line|
    line = line.strip
    next if line.empty?
    certs << Saro::Dat::DatCertificate.imports(line)
  end
  import_certificates(certs, clear: clear)
end

#issue(plain, secure) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/saro/dat/dat_manager.rb', line 75

def issue(plain, secure)
  state = @state
  issuer = state.issuer
  unless issuer
    raise Saro::Dat::Error.new(Saro::Dat::ErrorCode::MANAGER_NO_CERTIFICATE) if state.certificates.empty?
    raise Saro::Dat::Error.new(
      Saro::Dat::ErrorCode::MANAGER_NO_ISSUABLE_CERTIFICATE,
      cause: no_issuable_cause(state.certificates)
    )
  end

  self.class._issue(issuer, plain, secure)
end

#parse(dat_input) ⇒ Object

Raises:



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/saro/dat/dat_manager.rb', line 89

def parse(dat_input)
  dat = Saro::Dat::Dat.from_value(dat_input)
  dat.raise_if_invalid!

  raise Saro::Dat::Error.new(Saro::Dat::ErrorCode::TOKEN_EXPIRED) if dat.expired?

  certificate = @state.by_cid[dat.cid]
  unless certificate
    raise Saro::Dat::Error.new(Saro::Dat::ErrorCode::CERT_NOT_FOUND, "cid #{dat.cid.to_s(16)}")
  end

  self.class._parse(certificate, dat)
end