Class: KeeperSecretsManager::Notation::Parser
- Inherits:
-
Object
- Object
- KeeperSecretsManager::Notation::Parser
- Defined in:
- lib/keeper_secrets_manager/notation.rb,
lib/keeper_secrets_manager/notation_enhancements.rb
Overview
Parse and resolve keeper:// notation URIs
Defined Under Namespace
Classes: NotationSection
Constant Summary collapse
- ESCAPE_CHAR =
'\\'.freeze
- ESCAPE_CHARS =
Characters that can be escaped
'/[]\\'.freeze
Instance Method Summary collapse
-
#download_file(notation) ⇒ Object
Convenience method to download file content directly.
- #get_notation_results(notation) ⇒ Object
-
#get_totp_code(notation) ⇒ Object
Convenience method to get TOTP code directly.
-
#get_value(notation, options = {}) ⇒ Object
Get value with enhanced functionality This method extends the basic parse method to handle special cases.
-
#initialize(secrets_manager) ⇒ Parser
constructor
A new instance of Parser.
-
#parse(notation) ⇒ Object
Parse notation and return value.
Constructor Details
#initialize(secrets_manager) ⇒ Parser
Returns a new instance of Parser.
10 11 12 |
# File 'lib/keeper_secrets_manager/notation.rb', line 10 def initialize(secrets_manager) @secrets_manager = secrets_manager end |
Instance Method Details
#download_file(notation) ⇒ Object
Convenience method to download file content directly
62 63 64 |
# File 'lib/keeper_secrets_manager/notation_enhancements.rb', line 62 def download_file(notation) get_value(notation, auto_process: true, auto_download: true) end |
#get_notation_results(notation) ⇒ Object
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 |
# File 'lib/keeper_secrets_manager/notation.rb', line 14 def get_notation_results(notation) return [] if notation.nil? || !notation.is_a?(String) || notation.empty? parsed = parse_notation(notation) raise NotationError, "Invalid notation: #{notation}" if parsed.length < 3 record_token = parsed[1].text&.first selector = parsed[2].text&.first raise NotationError, 'Invalid notation: missing record' unless record_token raise NotationError, 'Invalid notation: missing selector' unless selector records = @secrets_manager.get_secrets([record_token]) if records.empty? all = @secrets_manager.get_secrets records = all.select { |r| r.title == record_token } end records = records.uniq { |r| r.uid } if records.size > 1 raise NotationError, "Multiple records match '#{record_token}'" if records.size > 1 raise NotationError, "No records match '#{record_token}'" if records.empty? record = records.first parameter = parsed[2].parameter&.first index1 = parsed[2].index1&.first index2 = parsed[2].index2&.first case selector.downcase when 'type' record.type ? [record.type] : [] when 'title' record.title ? [record.title] : [] when 'notes' (record.notes && !record.notes.empty?) ? [record.notes] : [] when 'file' notation_results_file(record, parameter, record_token) when 'field', 'custom_field' notation_results_field(record, parameter, index1, index2, parsed[2]) else raise NotationError, "Invalid selector: #{selector}" end end |
#get_totp_code(notation) ⇒ Object
Convenience method to get TOTP code directly
57 58 59 |
# File 'lib/keeper_secrets_manager/notation_enhancements.rb', line 57 def get_totp_code(notation) get_value(notation, auto_process: true, generate_totp_code: true) end |
#get_value(notation, options = {}) ⇒ Object
Get value with enhanced functionality This method extends the basic parse method to handle special cases
8 9 10 11 12 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 |
# File 'lib/keeper_secrets_manager/notation_enhancements.rb', line 8 def get_value(notation, = {}) return nil if notation.nil? || !notation.is_a?(String) || notation.empty? value = parse(notation) # Check if we should process special types return value unless [:auto_process] # Parse the notation to understand what we're dealing with parsed = parse_notation(notation) return value if parsed.length < 3 selector = parsed[2].text&.first return value unless selector case selector.downcase when 'file' # If it's a file and auto_download is enabled, download it if [:auto_download] && value.is_a?(Hash) && value['fileUid'] begin file_data = @secrets_manager.download_file(value['fileUid']) return file_data['data'] # Return file content rescue StandardError => e raise NotationError, "Failed to download file: #{e.}" end end when 'field' # Check if it's a TOTP field parameter = parsed[2].parameter&.first if parameter && parameter.downcase == 'onetimecode' && value.is_a?(String) && value.start_with?('otpauth://') && ([:generate_totp_code]) begin totp_params = TOTP.parse_url(value) return TOTP.generate_code( totp_params['secret'], algorithm: totp_params['algorithm'], digits: totp_params['digits'], period: totp_params['period'] ) rescue StandardError => e raise NotationError, "Failed to generate TOTP code: #{e.}" end end end value end |
#parse(notation) ⇒ Object
Parse notation and return value
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/keeper_secrets_manager/notation.rb', line 56 def parse(notation) return nil if notation.nil? raise NotationError, 'Invalid notation format: must be a string' unless notation.is_a?(String) return nil if notation.empty? # Parse notation URI begin parsed = parse_notation(notation) rescue StandardError => e raise NotationError, "Invalid notation format: #{e.}" end # Validate we have minimum required sections raise NotationError, "Invalid notation: #{notation}" if parsed.length < 3 # Extract components record_token = parsed[1].text&.first selector = parsed[2].text&.first raise NotationError, 'Invalid notation: missing record' unless record_token raise NotationError, 'Invalid notation: missing selector' unless selector # Get record records = @secrets_manager.get_secrets([record_token]) # If not found by UID, try by title if records.empty? all_records = @secrets_manager.get_secrets records = all_records.select { |r| r.title == record_token } end # Remove duplicate UIDs - shortcuts/linked records both shared to same KSM App records = records.uniq { |r| r.uid } if records.size > 1 # Now check for genuine ambiguity (different records with same title) raise NotationError, "Multiple records match '#{record_token}'" if records.size > 1 raise NotationError, "No records match '#{record_token}'" if records.empty? record = records.first # Extract parameters parameter = parsed[2].parameter&.first index1 = parsed[2].index1&.first index2 = parsed[2].index2&.first # Process selector case selector.downcase when 'type' record.type when 'title' record.title when 'notes' record.notes when 'file' handle_file_selector(record, parameter, record_token) when 'field', 'custom_field' handle_field_selector(record, selector, parameter, index1, index2, parsed[2]) else raise NotationError, "Invalid selector: #{selector}" end end |