github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/tests/system/lib/instance.rb (about)

     1  class Instance
     2    attr_reader :stack, :name, :domain, :email, :locale
     3    attr_accessor :passphrase
     4  
     5    def self.create(opts = {})
     6      stack = Stack.get opts.delete(:port)
     7      inst = Instance.new stack, opts
     8      stack.start
     9      stack.create_instance inst
    10      inst
    11    end
    12  
    13    def initialize(stack, opts = {})
    14      @stack = stack
    15      @name = opts[:name] || Faker::Internet.domain_word
    16      @domain = opts[:domain] || "#{@name.downcase}.test.localhost:#{stack.port}"
    17      @passphrase = opts[:passphrase] || "cozy" unless opts[:onboarded] == false
    18      @email = opts[:email] || "#{@name.downcase}+test@localhost"
    19      @locale = opts[:locale] || "fr"
    20    end
    21  
    22    def remove
    23      @stack.remove_instance self
    24    end
    25  
    26    def install_app(slug)
    27      @stack.install_app self, slug
    28    end
    29  
    30    def install_konnector(slug, source_url = nil)
    31      @stack.install_konnector self, slug, source_url
    32    end
    33  
    34    def remove_konnector(slug)
    35      @stack.remove_konnector self, slug
    36    end
    37  
    38    def run_konnector(slug, account_id)
    39      @stack.run_konnector self, slug, account_id
    40    end
    41  
    42    def run_job(type, args)
    43      @stack.run_job self, type, args
    44    end
    45  
    46    def setup_2fa
    47      @stack.setup_2fa self
    48    end
    49  
    50    def get_two_factor_code_from_mail(timeout = 30)
    51      timeout.times do
    52        sleep 1
    53        received = Email.received kind: "to", query: email
    54        received.select! { |e| e.subject =~ /One-time connection code/ }
    55        return extract_two_factor_code received.first if received.any?
    56      end
    57      raise "Mail with two-factor code was not received after #{timeout} seconds"
    58    end
    59  
    60    def extract_two_factor_code(mail)
    61      scanned = mail.body.scan(/: (\d{6})/)
    62      raise "No code in #{mail.subject} - #{mail.body}" if scanned.empty?
    63      scanned.last.last
    64    end
    65  
    66    def client
    67      @client ||= RestClient::Resource.new url
    68    end
    69  
    70    def url(obj = nil)
    71      case obj
    72      when Contact
    73        @stack.install_app self, "contacts"
    74        "http://contacts.#{@domain}/"
    75      when Folder
    76        @stack.install_app self, "drive"
    77        "http://drive.#{@domain}/"
    78      else
    79        "http://#{@domain}"
    80      end
    81    end
    82  
    83    def open(obj = nil, opts = {})
    84      browser = opts[:browser] || ENV['BROWSER'] || 'firefox'
    85      case browser
    86      when /firefox/
    87        `#{browser} -private-window #{url obj}`
    88      when /chrom/
    89        `#{browser} --incognito #{url obj}`
    90      else
    91        `#{browser} #{url obj}`
    92      end
    93    end
    94  
    95    def token_for(doctype)
    96      @stack.token_for self, [doctype]
    97    end
    98  
    99    def register(sharing)
   100      doctypes = sharing.rules.map(&:doctype).uniq
   101      token = @stack.token_for self, doctypes
   102      opts = {
   103        accept: "application/vnd.api+json",
   104        content_type: "application/vnd.api+json",
   105        authorization: "Bearer #{token}"
   106      }
   107      body = JSON.generate sharing.as_json_api
   108      res = @client["/sharings/"].post body, opts
   109      sharing.couch_id = JSON.parse(res.body)["data"]["id"]
   110    end
   111  
   112    def accept(sharing, sharer = nil)
   113      @stack.install_app self, "home"
   114      Accept.new(sharing, sharer).on self
   115    end
   116  
   117    def version
   118      res = @client["/version/"].get accept: "application/json"
   119      JSON.parse(res.body)
   120    end
   121  
   122    def fsck
   123      @stack.fsck self
   124    end
   125  
   126    def check
   127      @stack.check self
   128    end
   129  
   130    def open_session
   131      client = RestClient::Resource.new url
   132      res = client["/auth/login"].get
   133      csrf_token = res.cookies["_csrf"]
   134      body = { csrf_token: csrf_token, passphrase: hashed_passphrase }
   135      params = { cookies: res.cookies, accept: :json }
   136      res2 = client["/auth/login"].post body, params
   137      res2.cookies["cozysessid"]
   138    end
   139  
   140    # See https://github.com/jcs/rubywarden/blob/master/API.md#example
   141    def hashed_passphrase
   142      key = PBKDF2.new do |p|
   143        p.password = passphrase
   144        p.salt = "me@" + domain.split(':').first
   145        p.iterations = 650_000 # See pkg/crypto/pbkdf2.go
   146        p.hash_function = OpenSSL::Digest::SHA256
   147        p.key_length = 256 / 8
   148      end.bin_string
   149      hashed = PBKDF2.new do |p|
   150        p.password = key
   151        p.salt = passphrase
   152        p.iterations = 1
   153        p.hash_function = OpenSSL::Digest::SHA256
   154        p.key_length = 256 / 8
   155      end.bin_string
   156      Base64.strict_encode64 hashed
   157    end
   158  
   159    def register_token
   160      doc = Couch.new.instances.detect { |i| i["domain"] == @domain }
   161      token = Base64.decode64 doc["register_token"]
   162      Digest.hexencode token
   163    end
   164  end