Class: Zonesync::Manifest

Inherits:
Struct
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/zonesync/manifest.rb

Constant Summary collapse

DIFFABLE_RECORD_TYPES =
T.let(%w[A AAAA CNAME MX TXT SPF NAPTR PTR].sort, T::Array[String])

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#recordsObject

Returns the value of attribute records

Returns:

  • (Object)

    the current value of records



9
10
11
# File 'lib/zonesync/manifest.rb', line 9

def records
  @records
end

#zoneObject

Returns the value of attribute zone

Returns:

  • (Object)

    the current value of zone



9
10
11
# File 'lib/zonesync/manifest.rb', line 9

def zone
  @zone
end

Instance Method Details

#diffable?(record) ⇒ Boolean

Returns:

  • (Boolean)


60
61
62
63
64
65
66
# File 'lib/zonesync/manifest.rb', line 60

def diffable? record
  if existing?
    matches?(record)
  else
    DIFFABLE_RECORD_TYPES.include?(record.type)
  end
end

#existingObject



15
16
17
# File 'lib/zonesync/manifest.rb', line 15

def existing
  records.find(&:manifest?)
end

#existing?Boolean

Returns:

  • (Boolean)


20
21
22
# File 'lib/zonesync/manifest.rb', line 20

def existing?
  !!existing
end

#existing_checksumObject



30
31
32
# File 'lib/zonesync/manifest.rb', line 30

def existing_checksum
  records.find(&:checksum?)
end

#generateObject



25
26
27
# File 'lib/zonesync/manifest.rb', line 25

def generate
  generate_v2
end

#generate_checksumObject



35
36
37
38
39
40
41
42
43
44
45
# File 'lib/zonesync/manifest.rb', line 35

def generate_checksum
  input_string = diffable_records.map(&:to_s).join
  sha256 = Digest::SHA256.hexdigest(input_string)
  Record.new(
    name: "zonesync_checksum.#{zone.origin}",
    type: "TXT",
    ttl: 3600,
    rdata: sha256.inspect,
    comment: nil,
  )
end

#generate_v2Object



48
49
50
51
52
53
54
55
56
57
# File 'lib/zonesync/manifest.rb', line 48

def generate_v2
  hashes = diffable_records.map { |record| RecordHash.generate(record) }
  Record.new(
    name: "zonesync_manifest.#{zone.origin}",
    type: "TXT",
    ttl: 3600,
    rdata: hashes.join(',').inspect,
    comment: nil,
  )
end

#matches?(record) ⇒ Boolean

Returns:

  • (Boolean)


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/zonesync/manifest.rb', line 83

def matches? record
  return false unless existing?
  manifest_data = T.must(existing).rdata[1..-2] # remove quotes

  # Check if this is v2 format (comma-separated hashes) or v1 format (type:names)
  if manifest_data.include?(";")
    # V1 format: "A:@,mail;CNAME:www;MX:@ 10,@ 20"
    hash = manifest_data
      .split(";")
      .reduce({}) do |hash, pair|
        type, short_names = pair.split(":")
        hash[type] = short_names.split(",")
        hash
      end
    shorthands = hash.fetch(record.type, [])
    shorthands.include?(shorthand_for(record))
  else
    # V2 format: "1r81el0,60oib3,ky0g92,9pp0kg"
    expected_hashes = manifest_data.split(",")
    record_hash = RecordHash.generate(record)
    expected_hashes.include?(record_hash)
  end
end

#shorthand_for(record, with_type: false) ⇒ Object



108
109
110
111
112
113
114
115
# File 'lib/zonesync/manifest.rb', line 108

def shorthand_for record, with_type: false
  shorthand = record.short_name(zone.origin)
  shorthand = "#{record.type}:#{shorthand}" if with_type
  if record.type == "MX"
    shorthand += " #{record.rdata[/^\d+/]}"
  end
  shorthand
end

#v1_format?Boolean

Returns:

  • (Boolean)


69
70
71
72
73
74
# File 'lib/zonesync/manifest.rb', line 69

def v1_format?
  return false unless existing?
  manifest_data = T.must(existing).rdata[1..-2]
  # V1 format uses "TYPE:" syntax, v2 uses comma-separated hashes
  manifest_data.include?(":") || manifest_data.include?(";")
end

#v2_format?Boolean

Returns:

  • (Boolean)


77
78
79
80
# File 'lib/zonesync/manifest.rb', line 77

def v2_format?
  return false unless existing?
  !v1_format?
end