github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/tests/system/lib/oauth/client.rb (about) 1 module OAuth 2 class Client 3 attr_reader :client_id, :client_secret, :registration_token 4 5 def self.create(inst) 6 body = { 7 redirect_uris: ["cozy://"], 8 client_name: "test_#{Faker::Internet.slug}", 9 software_id: "github.com/cozy/cozy-stack/tests/system" 10 } 11 opts = { content_type: :json, accept: :json } 12 res = inst.client["/auth/register"].post body.to_json, opts 13 body = JSON.parse(res.body) 14 params = { 15 client_id: body["client_id"], 16 client_secret: body["client_secret"], 17 registration_token: body["registration_access_token"] 18 } 19 new params 20 end 21 22 def initialize(opts) 23 @client_id = opts[:client_id] 24 @client_secret = opts[:client_secret] 25 @registration_token = opts[:registration_token] 26 end 27 28 def register_passphrase(inst, pass) 29 inst.passphrase = pass 30 body = { 31 client_id: @client_id, 32 client_secret: @client_secret, 33 register_token: inst.register_token, 34 passphrase: inst.hashed_passphrase, 35 iterations: 650_000, 36 hint: "a hint to help me remember my passphrase", 37 key: "dont_care_key", 38 public_key: "dont_care_public_key", 39 private_key: "dont_care_private_key" 40 } 41 opts = { content_type: :json, accept: :json } 42 res = inst.client["/settings/passphrase/flagship"].post body.to_json, opts 43 JSON.parse(res.body)["session_code"] 44 end 45 46 def open_authorize_page(inst, session_code) 47 @authorize_params = [ 48 "session_code=#{session_code}", 49 "client_id=#{@client_id}", 50 "redirect_uri=cozy://", 51 "response_type=code", 52 "scope=*", 53 "state=state", 54 "code_challenge=LdAL134CIs7YgmZUganB2fkHMJ0W4F7QB6HqY5KEd6k", # "challenge" 55 "code_challenge_method=S256" 56 ].join('&') 57 inst.client["/auth/authorize?#{@authorize_params}"].get 58 end 59 60 def receive_flagship_code(inst, timeout = 30) 61 timeout.times do 62 sleep 1 63 received = Email.received kind: "to", query: inst.email 64 received.reject! { |e| e.subject =~ /(New.connection|Nouvelle.connexion)/ } 65 return extract_code received.first if received.any? 66 end 67 raise "Confirmation mail for moving was not received after #{timeout} seconds" 68 end 69 70 def extract_code(mail) 71 scanned = mail.body.scan(/^(\d{6})$/) 72 raise "No secret in #{mail.subject} - #{mail.body}" if scanned.empty? 73 scanned.last.last 74 end 75 76 def validate_flagship(inst, authorize_page, code) 77 opts = { 78 max_redirects: 0, 79 cookies: authorize_page.cookies 80 } 81 extracted = authorize_page.body.scan(/name="confirm-token" value="([^"]+)"/) 82 body = { token: extracted.first.first, code: code } 83 inst.client["/auth/clients/#{@client_id}/flagship"].post body, opts 84 inst.client["/auth/authorize?#{@authorize_params}"].get(opts) do |response| 85 params = extract_query_string response.headers[:location] 86 params["code"] 87 end 88 end 89 90 def access_token(inst, access_code) 91 body = { 92 grant_type: "authorization_code", 93 code: access_code, 94 client_id: @client_id, 95 client_secret: @client_secret, 96 code_verifier: "challenge" 97 } 98 opts = { accept: :json } 99 res = inst.client["/auth/access_token"].post body, opts 100 JSON.parse(res.body) 101 end 102 103 def extract_query_string(location) 104 query = URI.parse(location).query 105 CGI.parse(query).inject({}) do |h, (k, v)| 106 h[k] = v.first 107 h 108 end 109 end 110 111 def list_permissions(inst, tokens) 112 access_token = tokens["access_token"] 113 opts = { 114 accept: :json, 115 authorization: "Bearer #{access_token}" 116 } 117 res = inst.client["/permissions/self"].get opts 118 JSON.parse(res.body) 119 end 120 121 def create_session_code(inst) 122 body = { passphrase: inst.hashed_passphrase } 123 opts = { accept: :json, content_type: :json } 124 begin 125 res = inst.client["/auth/session_code"].post body.to_json, opts 126 rescue RestClient::Exception => e 127 token = JSON.parse(e.response.body)["two_factor_token"] 128 code = inst.get_two_factor_code_from_mail 129 body = { 130 passphrase: inst.hashed_passphrase, 131 two_factor_token: token, 132 two_factor_passcode: code 133 } 134 res = inst.client["/auth/session_code"].post body.to_json, opts 135 end 136 body = JSON.parse(res.body) 137 body["session_code"] 138 end 139 140 def destroy(inst) 141 opts = { authorization: "Bearer #{@registration_token}" } 142 inst.client["/auth/register/#{@client_id}"].delete opts 143 end 144 end 145 end