class AuthorizedKeys LINE = %r/^ (?: (? .+?) \s+)? (? (?:sk-)?ssh-[a-zA-Z0-9.@-]+) \s+ (? \S+) (?:\s+ (? .*) )? $/x def self.parse line opts, m = {}, LINE.match( line) raise "Invalid authorized keys line: #{line}" unless m if m[:options] o = m[:options].dup while not o.empty? case o when /^([a-z0-9_-]+)(.*)$/i k, o = $1.to_sym, $2 case o when '' then opts[k] = true when /^,(.*)$/ then opts[k], o = true, $1 when /^="([^"]*)"(.*)$/i, /^=([a-z_0-9:-]*)(.*?)$/i opts[k], o = $1, $2 case o when /^,(.*)/ then o = $1 when '' then o = '' else raise "Invalid options-string at: #{o}" end else raise "Invalid options-string at: #{o}" end when /^\s*#/ # comment end end end new m[:type], m[:key], m[:comment], **opts end attr_reader :type, :key, :comment, :options def initialize type, key, comment, **options @type, @key, @comment, @options = type, key, comment, options end def to_h() {type: @type, key: @key, comment: @comment, options: @options} end def to_a() [@type, @key, @comment, @options] end def to_s [ @options.map {|k,v| case v when true then "#{k}" else "#{k}=\"#{v}\"" end }.join( ','), @type, @key, @comment ].join ' ' end end