Class: KeeperSecretsManager::Dto::KeeperRecord

Inherits:
Object
  • Object
show all
Defined in:
lib/keeper_secrets_manager/dto.rb

Overview

Base class for dynamic record handling

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attrs = {}) ⇒ KeeperRecord

Returns a new instance of KeeperRecord.



13
14
15
16
17
18
19
20
21
22
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
# File 'lib/keeper_secrets_manager/dto.rb', line 13

def initialize(attrs = {})
  if attrs.is_a?(Hash)
    # Support both raw API response and user-friendly creation
    @uid = attrs['recordUid'] || attrs['uid'] || attrs[:uid]
    @folder_uid = attrs['folderUid'] || attrs['folder_uid'] || attrs[:folder_uid]
    @inner_folder_uid = attrs['innerFolderUid'] || attrs['inner_folder_uid'] || attrs[:inner_folder_uid]
    @revision = attrs['revision'] || attrs[:revision] || 0

    # Handle encrypted data or direct attributes
    if attrs['data']
      data = attrs['data'].is_a?(String) ? JSON.parse(attrs['data']) : attrs['data']
      @title = data['title'] || ''
      @type = data['type'] || 'login'
      @fields = data['fields'] || []
      @custom = data['custom'] || []
      @notes = data['notes'] || ''
    else
      @title = attrs['title'] || attrs[:title] || ''
      @type = attrs['type'] || attrs[:type] || 'login'
      @fields = attrs['fields'] || attrs[:fields] || []
      @custom = attrs['custom'] || attrs[:custom] || []
      @notes = attrs['notes'] || attrs[:notes] || ''
    end

    @files = attrs['files'] || attrs[:files] || []
    @links = attrs['links'] || attrs[:links] || []

    # Handle is_editable (can be false, so use has_key? check)
    if attrs.key?('isEditable')
      @is_editable = attrs['isEditable']
    elsif attrs.key?('is_editable')
      @is_editable = attrs['is_editable']
    elsif attrs.key?(:is_editable)
      @is_editable = attrs[:is_editable]
    else
      @is_editable = true  # Default to true if not specified
    end

    @data = attrs
  end

  # Ensure fields are always arrays of hashes
  normalize_fields!
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

Dynamic field access methods



142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/keeper_secrets_manager/dto.rb', line 142

def method_missing(method, *args, &block)
  method_name = method.to_s

  # Handle setters
  if method_name.end_with?('=')
    field_name = method_name.chomp('=')
    set_field(field_name, args.first)
  # Handle getters
  elsif common_field_types.include?(method_name)
    get_field_value_single(method_name)
  else
    super
  end
end

Instance Attribute Details

#customObject

Returns the value of attribute custom.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def custom
  @custom
end

#dataObject

Returns the value of attribute data.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def data
  @data
end

#fieldsObject

Returns the value of attribute fields.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def fields
  @fields
end

#filesObject

Returns the value of attribute files.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def files
  @files
end

#folder_uidObject

Returns the value of attribute folder_uid.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def folder_uid
  @folder_uid
end

#inner_folder_uidObject

Returns the value of attribute inner_folder_uid.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def inner_folder_uid
  @inner_folder_uid
end

#is_editableObject

Returns the value of attribute is_editable.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def is_editable
  @is_editable
end

Returns the value of attribute links.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def links
  @links
end

#notesObject

Returns the value of attribute notes.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def notes
  @notes
end

#record_keyObject (readonly)

Internal - stores decrypted record key (bytes) for file upload operations



11
12
13
# File 'lib/keeper_secrets_manager/dto.rb', line 11

def record_key
  @record_key
end

#revisionObject

Returns the value of attribute revision.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def revision
  @revision
end

#titleObject

Returns the value of attribute title.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def title
  @title
end

#typeObject

Returns the value of attribute type.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def type
  @type
end

#uidObject

Returns the value of attribute uid.



10
11
12
# File 'lib/keeper_secrets_manager/dto.rb', line 10

def uid
  @uid
end

Instance Method Details

#get_field(type_or_label) ⇒ Object

Find field by type or label (searches both fields and custom arrays)



77
78
79
80
81
82
83
84
# File 'lib/keeper_secrets_manager/dto.rb', line 77

def get_field(type_or_label)
  # Search in fields first
  field = fields.find { |f| f['type'] == type_or_label || f['label'] == type_or_label }
  return field if field

  # Search in custom fields
  custom.find { |f| f['type'] == type_or_label || f['label'] == type_or_label }
end

#get_field_value(type_or_label) ⇒ Object

Get field value (always returns array)



87
88
89
90
# File 'lib/keeper_secrets_manager/dto.rb', line 87

def get_field_value(type_or_label)
  field = get_field(type_or_label)
  field ? field['value'] || [] : []
end

#get_field_value_single(type_or_label) ⇒ Object

Get single field value (first element)



93
94
95
96
# File 'lib/keeper_secrets_manager/dto.rb', line 93

def get_field_value_single(type_or_label)
  values = get_field_value(type_or_label)
  values.first
end

Return this record's linked-credential entries as typed KeeperRecordLink objects.

Typed view over the raw links list (populated when secrets are fetched with QueryOptions(..., request_links: true)). The raw links list is left unchanged for backward compatibility; entries without a String recordUid are skipped.



130
131
132
133
134
135
136
137
138
139
# File 'lib/keeper_secrets_manager/dto.rb', line 130

def get_links
  (links || []).each_with_object([]) do |link_dict, result|
    next unless link_dict.is_a?(Hash)

    record_uid = link_dict['recordUid']
    next unless record_uid.is_a?(String) && !record_uid.empty?

    result << KeeperRecordLink.new(link_dict)
  end
end

#respond_to_missing?(method, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


157
158
159
160
# File 'lib/keeper_secrets_manager/dto.rb', line 157

def respond_to_missing?(method, include_private = false)
  method_name = method.to_s.chomp('=')
  common_field_types.include?(method_name) || super
end

#set_field(type, value, label = nil) ⇒ Object

Add or update field



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/keeper_secrets_manager/dto.rb', line 99

def set_field(type, value, label = nil)
  # Ensure value is an array
  value = [value] unless value.is_a?(Array)

  # Find existing field in both arrays
  existing = @fields.find { |f| f['type'] == type || (label && f['label'] == label) }
  existing ||= @custom.find { |f| f['type'] == type || (label && f['label'] == label) }

  if existing
    existing['value'] = value
    existing['label'] = label if label
  else
    new_field = { 'type' => type, 'value' => value }
    new_field['label'] = label if label

    # Decide which array to add to:
    # - If it has a label, it's a custom field
    # - If it's not a common field type, it's likely custom
    if label || !common_field_types.include?(type)
      @custom << new_field
    else
      @fields << new_field
    end
  end
end

#to_hObject

Convert to hash for API submission This should match the structure of the decrypted 'data' field from server (does NOT include uid, revision, folder_uid - those are in the outer payload)



61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/keeper_secrets_manager/dto.rb', line 61

def to_h
  result = {
    'title' => title,
    'type' => type,
    'fields' => fields
  }

  result['custom'] = custom unless custom.nil?

  # Only include notes if present
  result['notes'] = notes if notes && !notes.empty?

  result
end