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