spyri-api 0.1.6 → 0.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
  SHA256:
3
- metadata.gz: 17344ba07c89a16273c0bff7ba9044ef1e48c9547d8bc81ab21c38e53b8dd7b5
4
- data.tar.gz: 8083e38bf58b89956d98b1d3b53db5fbe631cc79a21c578ca0c0e422000b2ce2
3
+ metadata.gz: d8b61342fbeb952c4028674008db95f09e8eac633393250cb97c81755c61362d
4
+ data.tar.gz: 52900c1d81f36ccb3ffce84f5218bdd57cc3fe595d855fdda4dcc2bb9ccff856
5
5
  SHA512:
6
- metadata.gz: 5a5da8d6539bbff3995bf8c91a5a2ce36773d877c5474958fdbf2225683347fdcb0b7cb8803103e2c89076cbbdd3c0417b835ed804639ec3c0dcee929a6591e9
7
- data.tar.gz: f75bcef9e223862a1be4f24282dbc1b9d90113cbf9e286bd2d58fccfe58570b5c8dfe7238ba69259a9b0548fcb5eac034668f0e2dfe87d6c4954aa0ec530d575
6
+ metadata.gz: a4ee8a79feb0527a78e5b689f6c3cc2a384c39f18db9e20571d31686413da24d223e761873c4d746c8f20f1dcf8c52c68f0c7f7ca4ad2056d136fdcea76dd34b
7
+ data.tar.gz: d70111dd756ac295911276224452d076206c001be00a143b7167a7449262a7345141ed287d8daab54c060963765088d19d070dc103e06322511b79a5541055c5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [0.2.0] - 2026-10-27
2
+
3
+ - Sign requests with HMAC-SHA256 when `access_uuid` and `secret` are configured (bearer `access_token` still supported)
4
+ - Build the query string in the client instead of Excon, so that the signed path is the one sent
5
+
1
6
  ## [0.1.6] - 2025-07-08
2
7
 
3
8
  - Add modules & definitions endpoints
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- spyri-api (0.1.6)
4
+ spyri-api (0.2.0)
5
5
  excon
6
6
 
7
7
  GEM
@@ -54,7 +54,7 @@ GEM
54
54
  ruby-progressbar (1.13.0)
55
55
  unicode-display_width (3.1.4)
56
56
  unicode-emoji (~> 4.0, >= 4.0.4)
57
- unicode-emoji (4.0.4)
57
+ unicode-emoji (4.3.0)
58
58
 
59
59
  PLATFORMS
60
60
  ruby
data/README.md CHANGED
@@ -30,11 +30,12 @@ Or install it yourself as:
30
30
 
31
31
  ### Quickstart
32
32
 
33
+ Requests are signed with HMAC-SHA256:
33
34
  ```ruby
34
35
  begin
35
- client = SpyriApi::Client.new
36
- client.set_config({
37
- access_token: 'YOUR_SPYRI_API_TOKEN',
36
+ client = SpyriApi::Client.new({
37
+ access_uuid: 'YOUR_ACCESS_UUID',
38
+ secret: 'YOUR_SECRET',
38
39
  host: 'YOUR_SPYRI_API_URL'
39
40
  })
40
41
  users_endpoint = SpyriApi::Users.new(client)
@@ -1,14 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "json"
4
+ require "openssl"
5
+ require "uri"
6
+
3
7
  module SpyriApi
4
8
  class Client
5
9
 
10
+ SIGNATURE_SCHEME = "HMAC-SHA256"
11
+
6
12
  def initialize(config = {})
7
13
  set_config(config)
8
14
  end
9
15
 
10
16
  def set_config(config = {})
11
17
  @access_token = config[:access_token] || ''
18
+ # HMAC credentials: when both are given, requests are signed and the access token is not used
19
+ @access_uuid = config[:access_uuid]
20
+ @secret = config[:secret]
12
21
  @host = config[:host] || ''
13
22
 
14
23
  timeout = config[:timeout] || 120
@@ -18,17 +27,24 @@ module SpyriApi
18
27
  end
19
28
 
20
29
  def call_api(http_method, path, opts = {})
30
+ method = http_method.to_s.upcase
31
+ # The query string is built here rather than by Excon, so that the signed path is exactly the one sent
32
+ url = @host + path
33
+ query = URI.encode_www_form(opts[:query_params] || {})
34
+ url += "?#{query}" unless query.empty?
35
+ body = method == "GET" ? "" : opts[:body].to_json
36
+
21
37
  headers = {'Content-Type' => "application/json"}
22
- headers[:Authorization] = "Bearer #{@access_token}"
38
+ headers.merge!(authentication_headers(method, URI(url).request_uri, body))
23
39
 
24
- conn = Excon.new(@host + path, headers: headers, read_timeout: @read_timeout, write_timeout: @write_timeout, connect_timeout: @connect_timeout)
40
+ conn = Excon.new(url, headers: headers, read_timeout: @read_timeout, write_timeout: @write_timeout, connect_timeout: @connect_timeout)
25
41
 
26
42
  res = nil
27
- case http_method.to_sym.downcase
28
- when :post, :put, :patch, :delete
29
- res = conn.request(method: http_method, query: opts[:query_params], body: opts[:body].to_json)
30
- when :get
31
- res = conn.get(query: opts[:query_params])
43
+ case method
44
+ when "POST", "PUT", "PATCH", "DELETE"
45
+ res = conn.request(method: method, body: body)
46
+ when "GET"
47
+ res = conn.get
32
48
  end
33
49
 
34
50
  data = nil
@@ -41,5 +57,21 @@ module SpyriApi
41
57
  return data
42
58
  end
43
59
 
60
+ private
61
+
62
+ def hmac?
63
+ !@access_uuid.to_s.empty? && !@secret.to_s.empty?
64
+ end
65
+
66
+ def authentication_headers(method, request_uri, body)
67
+ # Legacy authentication: use Bearer token if HMAC credentials are not provided
68
+ return { 'Authorization' => "Bearer #{@access_token}" } unless hmac?
69
+
70
+ timestamp = Time.now.to_i.to_s
71
+ string_to_sign = [method, request_uri, timestamp, OpenSSL::Digest::SHA256.hexdigest(body)].join("\n")
72
+ signature = OpenSSL::HMAC.hexdigest('SHA256', @secret, string_to_sign)
73
+ { 'Authorization' => "#{SIGNATURE_SCHEME} access_uuid=#{@access_uuid};time=#{timestamp};signature=#{signature}" }
74
+ end
75
+
44
76
  end
45
- end
77
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SpyriApi
4
- VERSION = "0.1.6"
4
+ VERSION = "0.2.0"
5
5
  end
data/spyri-api.gemspec CHANGED
@@ -28,4 +28,6 @@ Gem::Specification.new do |spec|
28
28
 
29
29
  spec.add_dependency "excon"
30
30
 
31
+ spec.post_install_message = "From version 0.2.0, signature is made using an access_uuid and a secret, instead of the previous token (the token still works as a fallback)"
32
+
31
33
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spyri-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pabois
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-07-08 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: excon
@@ -24,7 +23,6 @@ dependencies:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
25
  version: '0'
27
- description:
28
26
  email:
29
27
  - pierreandre.boissinot@noesya.coop
30
28
  executables: []
@@ -59,7 +57,8 @@ metadata:
59
57
  homepage_uri: https://github.com/letemps-ch/spyri-api
60
58
  source_code_uri: https://github.com/letemps-ch/spyri-api
61
59
  changelog_uri: https://github.com/letemps-ch/spyri-api/CHANGELOG.md
62
- post_install_message:
60
+ post_install_message: From version 0.2.0, signature is made using an access_uuid and
61
+ a secret, instead of the previous token (the token still works as a fallback)
63
62
  rdoc_options: []
64
63
  require_paths:
65
64
  - lib
@@ -74,8 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
74
73
  - !ruby/object:Gem::Version
75
74
  version: '0'
76
75
  requirements: []
77
- rubygems_version: 3.5.16
78
- signing_key:
76
+ rubygems_version: 4.0.16
79
77
  specification_version: 4
80
78
  summary: Ruby client library for the Spyri API
81
79
  test_files: []