| 32 | | |
| | 37 | |
| | 38 | __PACKAGE__->mk_classdata(all_message_params => [ |
| | 39 | @{__PACKAGE__->required_message_params}, |
| | 40 | @{__PACKAGE__->optional_message_params}, |
| | 41 | ]); |
| | 42 | |
| | 43 | __PACKAGE__->mk_classdata(all_api_params => [ |
| | 44 | @{__PACKAGE__->required_api_params}, |
| | 45 | @{__PACKAGE__->optional_api_params}, |
| | 46 | ]); |
| | 47 | |
| | 48 | __PACKAGE__->mk_classdata(all_params => [ |
| | 49 | @{__PACKAGE__->all_api_params}, |
| | 50 | @{__PACKAGE__->all_message_params}, |
| | 51 | ]); |
| | 52 | |
| 39 | | |
| 40 | | sub add_required_request_params { |
| 41 | | my $class = shift; |
| 42 | | $class->required_request_params([@{$class->required_request_params}, @_]); |
| 43 | | $class->mk_accessors(@_); |
| 44 | | } |
| 45 | | |
| 46 | | sub add_optional_request_params { |
| 47 | | my $class = shift; |
| 48 | | $class->optional_request_params([@{$class->optional_request_params}, @_]); |
| 49 | | $class->mk_accessors(@_); |
| 50 | | } |
| 51 | | |
| 52 | | sub add_required_api_params { |
| 53 | | my $class = shift; |
| 54 | | $class->required_api_params([@{$class->required_api_params}, @_]); |
| 55 | | $class->mk_accessors(@_); |
| 56 | | } |
| 57 | | |
| 58 | | sub add_to_signature { |
| 59 | | my $class = shift; |
| 60 | | $class->signature_elements([@{$class->signature_elements}, @_]); |
| 61 | | } |
| 62 | | |
| 63 | | sub new { |
| 64 | | my $proto = shift; |
| 65 | | my $class = ref $proto || $proto; |
| 66 | | my %params = @_; |
| 67 | | $params{version} = '1.0' unless defined $params{version}; |
| 68 | | my $req = bless \%params, $class; |
| 69 | | $req->check; |
| 70 | | return $req; |
| 71 | | } |
| 72 | | |
| 73 | | sub check { |
| 74 | | my $self = shift; |
| 75 | | foreach my $k (@{$self->required_request_params}, @{$self->required_api_params}) { |
| 76 | | if (not defined $self->{$k}) { |
| 77 | | die "Missing required parameter '$k'"; |
| 78 | | } |
| 79 | | } |
| 80 | | if ($self->{extra_params} and $self->allow_extra_params) { |
| 81 | | foreach my $k (keys %{$self->{extra_params}}) { |
| 82 | | if ($k =~ /^oauth_/) { |
| 83 | | die "Parameter '$k' not allowed in arbitrary params" |
| 84 | | } |
| 85 | | } |
| 86 | | } |
| 87 | | } |
| 88 | | |
| 89 | | sub encode { |
| 90 | | my $str = shift; |
| 91 | | $str = "" unless defined $str; |
| 92 | | return URI::Escape::uri_escape_utf8($str,'^\w.~-'); |
| 93 | | } |
| 94 | | |
| 95 | | sub decode { |
| 96 | | my $str = shift; |
| 97 | | return uri_unescape($str); |
| 98 | | } |
| 99 | | |
| 100 | | sub allow_extra_params {1} |
| 101 | | |
| 102 | | sub gather_request_parameters { |
| 103 | | my $self = shift; |
| 104 | | my %opts = @_; |
| 105 | | $opts{quote} = "" unless defined $opts{quote}; |
| 106 | | $opts{params} ||= []; |
| 107 | | my %params; |
| 108 | | foreach my $k (@{$self->required_request_params}, @{$self->optional_request_params}, @{$opts{add}}) { |
| 109 | | $params{"oauth_$k"} = $self->$k; |
| 110 | | } |
| 111 | | if ($self->{extra_params} and !$opts{no_extra} and $self->allow_extra_params) { |
| 112 | | foreach my $k (keys %{$self->{extra_params}}) { |
| 113 | | $params{$k} = $self->{extra_params}{$k}; |
| 114 | | } |
| 115 | | } |
| 116 | | if ($opts{hash}) { |
| 117 | | return \%params; |
| 118 | | } |
| 119 | | my @pairs; |
| 120 | | while (my ($k,$v) = each %params) { |
| 121 | | push @pairs, join('=', encode($k), $opts{quote} . encode($v) . $opts{quote}); |
| 122 | | } |
| 123 | | return sort(@pairs); # sort not required here but makes module more testable |
| 124 | | } |
| 125 | | |
| 126 | | sub normalized_request_parameters { |
| 127 | | my $self = shift; |
| 128 | | return join('&', $self->gather_request_parameters); |
| 129 | | } |
| 130 | | |
| 131 | | sub signature_base_string { |
| 132 | | my $self = shift; |
| 133 | | return join('&', map(encode($self->$_), @{$self->signature_elements})); |
| 134 | | } |
| 145 | | } |
| 146 | | |
| 147 | | sub sign { |
| 148 | | my $self = shift; |
| 149 | | my $class = $self->_signature_method_class; |
| 150 | | $self->signature($class->sign($self, @_)); |
| 151 | | } |
| 152 | | |
| 153 | | sub verify { |
| 154 | | my $self = shift; |
| 155 | | my $class = $self->_signature_method_class; |
| 156 | | return $class->verify($self, @_); |
| 157 | | } |
| 158 | | |
| 159 | | sub _signature_method_class { |
| 160 | | my $self = shift; |
| 161 | | (my $signature_method = $self->signature_method) =~ s/\W+/_/g; |
| 162 | | my $klass = 'Net::OAuth::SignatureMethod::' . $signature_method; |
| 163 | | $klass->require or die "Unable to load $signature_method plugin"; |
| 164 | | return $klass; |
| 165 | | } |
| 166 | | |
| 167 | | sub to_authorization_header { |
| 168 | | my $self = shift; |
| 169 | | my $realm = shift; |
| 170 | | my $sep = shift || ","; |
| 171 | | return join($sep, "OAuth realm=\"$realm\"", |
| 172 | | $self->gather_request_parameters(quote => '"', add => [qw/signature/], no_extra => 1)); |
| 173 | | } |
| 174 | | |
| 175 | | sub from_authorization_header { |
| 176 | | my $proto = shift; |
| 177 | | my $class = ref $proto || $proto; |
| 178 | | my $header = shift; |
| 179 | | my %extra_params = @_; |
| 180 | | my @header = split /[\s]*,[\s]*/, $header; |
| 181 | | shift @header; |
| 182 | | my %params; |
| 183 | | foreach my $pair (@header) { |
| 184 | | my ($k,$v) = split /=/, $pair; |
| 185 | | if (defined $k and defined $v) { |
| 186 | | $v =~ s/(^"|"$)//g; |
| 187 | | ($k,$v) = map decode($_), $k, $v; |
| 188 | | $k =~ s/^oauth_//; |
| 189 | | $params{$k} = $v; |
| 190 | | } |
| 191 | | } |
| 192 | | return $class->new(%params, %extra_params); |
| 193 | | } |
| 194 | | |
| 195 | | sub to_post_body { |
| 196 | | my $self = shift; |
| 197 | | return join('&', $self->gather_request_parameters(add => [qw/signature/])); |
| 198 | | } |
| 199 | | |
| 200 | | sub to_hash { |
| 201 | | my $self = shift; |
| 202 | | return $self->gather_request_parameters(hash => 1, add => [qw/signature/]); |