openstax_api 8.1.1 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aeefa4b58e29cb1960801da52f27d4cfc2959c70
4
- data.tar.gz: 0cbdbded9beb84362074744d95168defa1e4f000
3
+ metadata.gz: a3da970c8b505007a77d4c22af9f93f02598a7ac
4
+ data.tar.gz: 5550c22216fd6b3792b04b182995f4b97a23edfd
5
5
  SHA512:
6
- metadata.gz: 0915a7de958c62ae641ff20b14381ce26781f660cc03a050da2444c2bd1ecfc3a00c41b4c105d049852c5960b381f02ddb343a1b824d0573f670b1dc12dca801
7
- data.tar.gz: 28fde8f8c2a57657fa08882cca2037f28fc6ccd3618480edbbc5fa16776e45b56cafdc9df60dcc79534a0f86d69d44dbc66a0c925e567f4386df7c38541f9f43
6
+ metadata.gz: 3beef5dc60cc89ca7eef3af6056973ca999a24c998ac017595d4d2c6141bce3a5e7c88fa78ec368caf994dbec04a63245b915e7ab5f6942208ff59c1139221df
7
+ data.tar.gz: a9887c1adbdbc5bc1b66ebb244c8b1069864613bf7ed34d1e7f024fe23383fc85f43deceda938eefa1885c77abc3f31c7cdee66b7fa22cc5fa1454153aab4845
@@ -6,6 +6,7 @@ require 'openstax_utilities'
6
6
  require 'openstax/api/roar'
7
7
  require 'openstax/api/apipie'
8
8
  require 'openstax/api/responder_with_put_patch_delete_content'
9
+ require 'openstax/api/params'
9
10
 
10
11
  module OpenStax
11
12
  module Api
@@ -0,0 +1,92 @@
1
+ module OpenStax
2
+ module Api
3
+ module Params
4
+
5
+ extend self
6
+
7
+ def sign(params:, secret:, algorithm: 'sha256')
8
+ raise "`secret` cannot be blank" if secret.blank?
9
+ local_params = params.merge(timestamp: Time.now.to_i)
10
+
11
+ stringified_params = normalize(local_params)
12
+ signature = OpenSSL::HMAC.hexdigest(algorithm, secret, stringified_params)
13
+
14
+ local_params.merge!(signature: signature)
15
+ end
16
+
17
+ def signature_and_timestamp_valid?(params:, secret:, algorithm: 'sha256', timestamp_window_width: 2.minutes)
18
+ local_params = params.dup
19
+ incoming_signature = local_params.delete(:signature)
20
+
21
+ return false if incoming_signature.blank?
22
+
23
+ stringified_params = normalize(local_params)
24
+ expected_signature = OpenSSL::HMAC.hexdigest(algorithm, secret, stringified_params)
25
+
26
+ return false if expected_signature != incoming_signature
27
+
28
+ timestamp_window = timestamp_window_width.ago..timestamp_window_width.from_now
29
+ return false if !timestamp_window.cover?(Time.at(params[:timestamp].to_i))
30
+
31
+ return true
32
+ end
33
+
34
+ # Below is borrowed from https://github.com/oauth-xx/oauth-ruby/blob/e397b3e2f540faaebd7912aeb2768835d151f795/lib/oauth/helper.rb
35
+ # so we can call `normalize` on some params without adding dependence on full oauth gem
36
+
37
+ RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~]/
38
+
39
+ # Escape +value+ by URL encoding all non-reserved character.
40
+ def escape(value)
41
+ _escape(value.to_s.to_str)
42
+ rescue ArgumentError
43
+ _escape(value.to_s.to_str.force_encoding(Encoding::UTF_8))
44
+ end
45
+
46
+ def _escape(string)
47
+ URI.escape(string, RESERVED_CHARACTERS)
48
+ end
49
+
50
+ # Normalize a +Hash+ of parameter values. Parameters are sorted by name, using lexicographical
51
+ # byte value ordering. If two or more parameters share the same name, they are sorted by their value.
52
+ # Parameters are concatenated in their sorted order into a single string. For each parameter, the name
53
+ # is separated from the corresponding value by an "=" character, even if the value is empty. Each
54
+ # name-value pair is separated by an "&" character.
55
+ def normalize(params)
56
+ params.sort.map do |k, values|
57
+ if values.is_a?(Array)
58
+ # make sure the array has an element so we don't lose the key
59
+ values << nil if values.empty?
60
+ # multiple values were provided for a single key
61
+ values.sort.collect do |v|
62
+ [escape(k),escape(v)] * "="
63
+ end
64
+ elsif values.is_a?(Hash)
65
+ normalize_nested_query(values, k)
66
+ else
67
+ [escape(k),escape(values)] * "="
68
+ end
69
+ end * "&"
70
+ end
71
+
72
+ #Returns a string representation of the Hash like in URL query string
73
+ # build_nested_query({:level_1 => {:level_2 => ['value_1','value_2']}}, 'prefix'))
74
+ # #=> ["prefix%5Blevel_1%5D%5Blevel_2%5D%5B%5D=value_1", "prefix%5Blevel_1%5D%5Blevel_2%5D%5B%5D=value_2"]
75
+ def normalize_nested_query(value, prefix = nil)
76
+ case value
77
+ when Array
78
+ value.map do |v|
79
+ normalize_nested_query(v, "#{prefix}[]")
80
+ end.flatten.sort
81
+ when Hash
82
+ value.map do |k, v|
83
+ normalize_nested_query(v, prefix ? "#{prefix}[#{k}]" : k)
84
+ end.flatten.sort
85
+ else
86
+ [escape(prefix), escape(value)] * "="
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
@@ -44,7 +44,9 @@ module OpenStax
44
44
 
45
45
  representer.representable_attrs.each do |attr|
46
46
  # Handle some common attributes (as, schema_info, required)
47
- name = attr[:as].blank? ? attr[:name] : attr[:as].evaluate(representer) rescue attr[:name]
47
+ name = attr[:as].blank? ?
48
+ attr[:name] :
49
+ attr[:as].evaluate(representer) rescue attr[:as].call rescue attr[:name]
48
50
  schema_info = attr[:schema_info] || {}
49
51
 
50
52
  schema[:required].push(name.to_sym) if schema_info[:required]
@@ -1,5 +1,5 @@
1
1
  module OpenStax
2
2
  module Api
3
- VERSION = "8.1.1"
3
+ VERSION = "8.2.0"
4
4
  end
5
5
  end
Binary file