Module: GrapeTokenAuth::PasswordAPICore

Included in:
PasswordAPI
Defined in:
lib/grape_token_auth/apis/password_api.rb

Overview

Module that contains the majority of the password reseting functionality. This module can be included in a Grape::API class that defines a resource_scope and therefore have all of the functionality with a given resource (mapping).

Class Method Summary collapse

Class Method Details

.included(base) ⇒ Object



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
55
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
117
118
119
120
121
# File 'lib/grape_token_auth/apis/password_api.rb', line 8

def self.included(base)
  base.helpers do
    def throw_unauthorized(message)
      throw(:warden, errors: message)
    end

    def bad_request(messages, code = 422)
      status(code)
      { 'status' => 'error', 'error' => messages.join(',') }
    end

    def validate_redirect_url!(url)
      white_list = GrapeTokenAuth.configuration.redirect_whitelist
      return unless white_list
      url_valid = white_list.include?(url)
      error!({ errors: 'redirect url is not in whitelist', status: 'error' }, 403) unless url_valid
    end
  end

  base.post do
    email = params[:email]
    throw_unauthorized('You must provide an email address.') unless email

    redirect_url = params[:redirect_url]
    validate_redirect_url!(redirect_url)
    redirect_url ||= GrapeTokenAuth.configuration.default_password_reset_url
    throw_unauthorized('Missing redirect url.') unless redirect_url
    resource = ResourceFinder.find(base.resource_scope, params)
    edit_path = routes[0].path.gsub(/\(.*\)/, '') + "/edit"
    if resource
      resource.send_reset_password_instructions(
        provider: 'email',
        redirect_url: redirect_url,
        client_config: params[:config_name],
        edit_path: edit_path
      )

      if resource.errors.empty?
        status 200
        present(success: true,
                message: "An email has been sent to #{email} containing " +
                         'instructions for resetting your password.'
               )
      else
        return error!({ errors: resource.errors,
                        status: 'error' }, 400)
      end
    else
      error!({ errors: "Unable to find user with email '#{email}'.",
               status: 'error' }, 404)
    end
  end

  base.get '/edit' do
    resource_class = GrapeTokenAuth.configuration.scope_to_class(base.resource_scope)
    resource = resource_class.find_with_reset_token(
      reset_password_token: params[:reset_password_token]
    )

    if resource
      token = Token.new

      resource.tokens[token.client_id] = {
        token:  token.to_password_hash,
        expiry: token.expiry
      }

      resource.confirm unless resource.confirmed?

      # TODO: ensure that user is confirmed
      # @resource.skip_confirmation! if @resource.devise_modules.include?(:confirmable) && [email protected]_at

      resource.save!

      redirect_url = resource.build_auth_url(
        params[:redirect_url], token: token.to_s, reset_password: true,
                               client_id: token.client_id,
                               config: params[:config])
      redirect redirect_url
    else
      error!({ success: false }, 404)
    end
  end

  base.put do
    token_authorizer = TokenAuthorizer.new(AuthorizerData.from_env(env))
    resource = token_authorizer.find_resource(base.resource_scope)
    throw(:warden) unless resource
    unless resource.provider == 'email'
      error!({ errors: 'Password not required.',
               status: 'error', success: false }, 422)
    end
    # ensure that password params were sent
    unless params[:password] && params[:password_confirmation]
      error!({ errors: 'Passwords are missing.',
               status: 'error', success: false }, 422)
    end

    # TODO: previous password confirmation
    if resource.reset_password(params[:password], params[:password_confirmation])
      return present json: {
        success: true,
        data: {
          user: resource,
          message: 'Successfully updated'
        }
      }
    else
      error!({ success: false,
        errors: resource.errors.to_hash.merge(full_messages: resource.errors.full_messages)
      }, 422)
    end
  end
end