remitmd 0.1.9 → 0.2.1
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 +4 -4
- data/README.md +12 -8
- data/lib/remitmd/cli_signer.rb +136 -0
- data/lib/remitmd/wallet.rb +14 -10
- data/lib/remitmd.rb +2 -2
- metadata +2 -2
- data/lib/remitmd/http_signer.rb +0 -200
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 75be0a5249f87323f7c007b13b7b89f9e2153557b355381000b7d3d007adcfc0
|
|
4
|
+
data.tar.gz: e0f9b80bc11f7eb9888f037cba3589548a3344bdba9f621994142f5b20a3b14d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5198b515870956a99eccee4152e991d4fc32f6f03acd5a91a499b9c853b57da2c0b3cad4657381e1524553f10d021415b1d9202ce35848eb06331e5420758c73
|
|
7
|
+
data.tar.gz: 5bcaab9bc1d75389f524ad3ab36920a02bf9dbacf68792c6492f8bc04a6ebb2197725a73342191a26c2debf7dceddf31a3247968e82f470c228fe76203a51df0
|
data/README.md
CHANGED
|
@@ -39,31 +39,35 @@ Or from environment variables:
|
|
|
39
39
|
|
|
40
40
|
```ruby
|
|
41
41
|
wallet = Remitmd::RemitWallet.from_env
|
|
42
|
-
#
|
|
42
|
+
# Auto-detects: CliSigner (remit CLI) > REMITMD_KEY
|
|
43
43
|
# Optional: REMITMD_CHAIN (default: "base"), REMITMD_API_URL
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
Permits are auto-signed. Every payment method fetches the on-chain USDC nonce, signs an EIP-2612 permit, and includes it automatically.
|
|
47
47
|
|
|
48
|
-
##
|
|
48
|
+
## CLI Signer (Recommended)
|
|
49
49
|
|
|
50
|
-
The
|
|
50
|
+
The CLI signer delegates key management to the `remit` CLI binary, which holds your encrypted keystore at `~/.remit/keys/`. No private key in your environment -- just install the CLI and set a password.
|
|
51
51
|
|
|
52
52
|
```bash
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
# Install the CLI
|
|
54
|
+
# macOS: brew install remit-md/tap/remit
|
|
55
|
+
# Windows: winget install remit-md.remit
|
|
56
|
+
# Linux: curl -fsSL https://remit.md/install.sh | sh
|
|
57
|
+
|
|
58
|
+
export REMIT_KEY_PASSWORD=your-keystore-password
|
|
55
59
|
```
|
|
56
60
|
|
|
57
61
|
```ruby
|
|
58
62
|
# Explicit
|
|
59
|
-
signer = Remitmd::
|
|
63
|
+
signer = Remitmd::CliSigner.new
|
|
60
64
|
wallet = Remitmd::RemitWallet.new(signer: signer)
|
|
61
65
|
|
|
62
66
|
# Or auto-detect from env (recommended)
|
|
63
|
-
wallet = Remitmd::RemitWallet.from_env # detects
|
|
67
|
+
wallet = Remitmd::RemitWallet.from_env # detects remit CLI automatically
|
|
64
68
|
```
|
|
65
69
|
|
|
66
|
-
`RemitWallet.from_env` detects
|
|
70
|
+
`RemitWallet.from_env` detects signing methods automatically. Priority: `CliSigner` (CLI + keystore + password) > `REMITMD_KEY`.
|
|
67
71
|
|
|
68
72
|
## Payment Models
|
|
69
73
|
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
|
|
5
|
+
module Remitmd
|
|
6
|
+
# Signer backed by the `remit sign` CLI command.
|
|
7
|
+
#
|
|
8
|
+
# No key material in this process -- signing happens in a subprocess.
|
|
9
|
+
# Address is cached at construction time via `remit address`.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# signer = Remitmd::CliSigner.new
|
|
13
|
+
# wallet = Remitmd::RemitWallet.new(signer: signer, chain: "base")
|
|
14
|
+
#
|
|
15
|
+
class CliSigner
|
|
16
|
+
include Signer
|
|
17
|
+
|
|
18
|
+
# Default timeout for CLI subprocess calls (seconds).
|
|
19
|
+
CLI_TIMEOUT = 10
|
|
20
|
+
|
|
21
|
+
# Create a CliSigner, fetching and caching the wallet address.
|
|
22
|
+
#
|
|
23
|
+
# @param cli_path [String] path or name of the remit CLI binary (default: "remit")
|
|
24
|
+
# @raise [RemitError] if the CLI fails or returns an invalid address
|
|
25
|
+
def initialize(cli_path: "remit")
|
|
26
|
+
@cli_path = cli_path
|
|
27
|
+
@address = fetch_address
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Sign a 32-byte digest (raw binary bytes).
|
|
31
|
+
# Pipes the hex-encoded digest to `remit sign --digest` on stdin.
|
|
32
|
+
# Returns a 0x-prefixed 65-byte hex signature.
|
|
33
|
+
#
|
|
34
|
+
# @param digest_bytes [String] 32-byte binary digest
|
|
35
|
+
# @return [String] 0x-prefixed 130-char hex signature (65 bytes)
|
|
36
|
+
# @raise [RemitError] on CLI failure or invalid output
|
|
37
|
+
def sign(digest_bytes)
|
|
38
|
+
hex = digest_bytes.unpack1("H*")
|
|
39
|
+
stdout, stderr, status = run_cli("sign", "--digest", stdin_data: hex)
|
|
40
|
+
|
|
41
|
+
unless status.success?
|
|
42
|
+
raise RemitError.new(
|
|
43
|
+
RemitError::SERVER_ERROR,
|
|
44
|
+
"CliSigner: signing failed: #{stderr.strip}"
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
sig = stdout.strip
|
|
49
|
+
unless sig.start_with?("0x") && sig.length == 132
|
|
50
|
+
raise RemitError.new(
|
|
51
|
+
RemitError::SERVER_ERROR,
|
|
52
|
+
"CliSigner: invalid signature from CLI: #{sig}"
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
sig
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# The cached Ethereum address (0x-prefixed).
|
|
60
|
+
# @return [String]
|
|
61
|
+
attr_reader :address
|
|
62
|
+
|
|
63
|
+
# Never expose internals in inspect/to_s output.
|
|
64
|
+
def inspect
|
|
65
|
+
"#<Remitmd::CliSigner address=#{@address}>"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
alias to_s inspect
|
|
69
|
+
|
|
70
|
+
# Check all three conditions for CliSigner activation.
|
|
71
|
+
#
|
|
72
|
+
# 1. CLI binary found on PATH (via `which` / `where`)
|
|
73
|
+
# 2. Keystore file exists at ~/.remit/keys/default.enc
|
|
74
|
+
# 3. REMIT_KEY_PASSWORD env var is set
|
|
75
|
+
#
|
|
76
|
+
# @param cli_path [String] path or name of the remit CLI binary
|
|
77
|
+
# @return [Boolean]
|
|
78
|
+
def self.available?(cli_path: "remit")
|
|
79
|
+
# 1. CLI binary on PATH
|
|
80
|
+
which_cmd = Gem.win_platform? ? "where" : "which"
|
|
81
|
+
_out, _err, st = Open3.capture3(which_cmd, cli_path)
|
|
82
|
+
return false unless st.success?
|
|
83
|
+
|
|
84
|
+
# 2. Keystore file exists
|
|
85
|
+
keystore = File.join(Dir.home, ".remit", "keys", "default.enc")
|
|
86
|
+
return false unless File.exist?(keystore)
|
|
87
|
+
|
|
88
|
+
# 3. REMIT_KEY_PASSWORD set
|
|
89
|
+
password = ENV["REMIT_KEY_PASSWORD"]
|
|
90
|
+
return false if password.nil? || password.empty?
|
|
91
|
+
|
|
92
|
+
true
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
# Fetch the wallet address from `remit address` during construction.
|
|
98
|
+
# @return [String] the 0x-prefixed Ethereum address
|
|
99
|
+
# @raise [RemitError] on any failure
|
|
100
|
+
def fetch_address
|
|
101
|
+
stdout, stderr, status = run_cli("address")
|
|
102
|
+
|
|
103
|
+
unless status.success?
|
|
104
|
+
raise RemitError.new(
|
|
105
|
+
RemitError::SERVER_ERROR,
|
|
106
|
+
"CliSigner: failed to get address: #{stderr.strip}"
|
|
107
|
+
)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
addr = stdout.strip
|
|
111
|
+
unless addr.match?(/\A0x[0-9a-fA-F]{40}\z/)
|
|
112
|
+
raise RemitError.new(
|
|
113
|
+
RemitError::SERVER_ERROR,
|
|
114
|
+
"CliSigner: invalid address from CLI: #{addr}"
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
addr
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Run the remit CLI with given arguments.
|
|
122
|
+
# @param args [Array<String>] CLI arguments
|
|
123
|
+
# @param stdin_data [String, nil] data to pipe to stdin
|
|
124
|
+
# @return [Array<String, String, Process::Status>] stdout, stderr, status
|
|
125
|
+
# @raise [RemitError] on timeout or execution failure
|
|
126
|
+
def run_cli(*args, stdin_data: nil)
|
|
127
|
+
Open3.capture3(@cli_path, *args, stdin_data: stdin_data.to_s)
|
|
128
|
+
rescue Errno::ENOENT
|
|
129
|
+
raise RemitError.new(
|
|
130
|
+
RemitError::SERVER_ERROR,
|
|
131
|
+
"CliSigner: remit CLI not found at '#{@cli_path}'. " \
|
|
132
|
+
"Install: https://remit.md/install"
|
|
133
|
+
)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
data/lib/remitmd/wallet.rb
CHANGED
|
@@ -67,21 +67,16 @@ module Remitmd
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
# Build a RemitWallet from environment variables.
|
|
70
|
-
#
|
|
71
|
-
# or REMITMD_KEY (primary) / REMITMD_PRIVATE_KEY (deprecated fallback).
|
|
70
|
+
# Priority: CliSigner (if available) > REMITMD_KEY / REMITMD_PRIVATE_KEY.
|
|
72
71
|
# Also reads: REMITMD_CHAIN, REMITMD_API_URL, REMITMD_ROUTER_ADDRESS.
|
|
73
72
|
def self.from_env
|
|
74
73
|
chain = ENV.fetch("REMITMD_CHAIN", "base")
|
|
75
74
|
api_url = ENV["REMITMD_API_URL"]
|
|
76
75
|
router_address = ENV["REMITMD_ROUTER_ADDRESS"]
|
|
77
76
|
|
|
78
|
-
# Priority 1:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
signer_token = ENV["REMIT_SIGNER_TOKEN"]
|
|
82
|
-
raise ArgumentError, "REMIT_SIGNER_TOKEN must be set when REMIT_SIGNER_URL is set" unless signer_token
|
|
83
|
-
|
|
84
|
-
signer = HttpSigner.new(url: signer_url, token: signer_token)
|
|
77
|
+
# Priority 1: CLI signer (remit binary + keystore + password)
|
|
78
|
+
if CliSigner.available?
|
|
79
|
+
signer = CliSigner.new
|
|
85
80
|
return new(signer: signer, chain: chain, api_url: api_url, router_address: router_address)
|
|
86
81
|
end
|
|
87
82
|
|
|
@@ -90,7 +85,16 @@ module Remitmd
|
|
|
90
85
|
if ENV["REMITMD_PRIVATE_KEY"] && !ENV["REMITMD_KEY"]
|
|
91
86
|
warn "[remitmd] REMITMD_PRIVATE_KEY is deprecated, use REMITMD_KEY instead"
|
|
92
87
|
end
|
|
93
|
-
|
|
88
|
+
|
|
89
|
+
unless key
|
|
90
|
+
raise ArgumentError,
|
|
91
|
+
"No signing method available. Either:\n" \
|
|
92
|
+
" 1. Install the remit CLI and set REMIT_KEY_PASSWORD:\n" \
|
|
93
|
+
" macOS: brew install remit-md/tap/remit\n" \
|
|
94
|
+
" Windows: winget install remit-md.remit\n" \
|
|
95
|
+
" Linux: curl -fsSL https://remit.md/install.sh | sh\n" \
|
|
96
|
+
" 2. Set REMITMD_KEY to a raw private key (hex)"
|
|
97
|
+
end
|
|
94
98
|
|
|
95
99
|
new(private_key: key, chain: chain, api_url: api_url, router_address: router_address)
|
|
96
100
|
end
|
data/lib/remitmd.rb
CHANGED
|
@@ -4,7 +4,7 @@ require_relative "remitmd/errors"
|
|
|
4
4
|
require_relative "remitmd/models"
|
|
5
5
|
require_relative "remitmd/keccak"
|
|
6
6
|
require_relative "remitmd/signer"
|
|
7
|
-
require_relative "remitmd/
|
|
7
|
+
require_relative "remitmd/cli_signer"
|
|
8
8
|
require_relative "remitmd/http"
|
|
9
9
|
require_relative "remitmd/wallet"
|
|
10
10
|
require_relative "remitmd/mock"
|
|
@@ -26,5 +26,5 @@ require_relative "remitmd/x402_paywall"
|
|
|
26
26
|
# mock.was_paid?("0x0000000000000000000000000000000000000001", 1.00) # => true
|
|
27
27
|
#
|
|
28
28
|
module Remitmd
|
|
29
|
-
VERSION = "0.1
|
|
29
|
+
VERSION = "0.2.1"
|
|
30
30
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: remitmd
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- remit.md
|
|
@@ -51,9 +51,9 @@ files:
|
|
|
51
51
|
- README.md
|
|
52
52
|
- lib/remitmd.rb
|
|
53
53
|
- lib/remitmd/a2a.rb
|
|
54
|
+
- lib/remitmd/cli_signer.rb
|
|
54
55
|
- lib/remitmd/errors.rb
|
|
55
56
|
- lib/remitmd/http.rb
|
|
56
|
-
- lib/remitmd/http_signer.rb
|
|
57
57
|
- lib/remitmd/keccak.rb
|
|
58
58
|
- lib/remitmd/mock.rb
|
|
59
59
|
- lib/remitmd/models.rb
|
data/lib/remitmd/http_signer.rb
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "net/http"
|
|
4
|
-
require "uri"
|
|
5
|
-
require "json"
|
|
6
|
-
|
|
7
|
-
module Remitmd
|
|
8
|
-
# Signer backed by a local HTTP signing server.
|
|
9
|
-
#
|
|
10
|
-
# Delegates digest signing to an HTTP server (typically
|
|
11
|
-
# `http://127.0.0.1:7402`). The signer server holds the encrypted key;
|
|
12
|
-
# this adapter only needs a bearer token and URL.
|
|
13
|
-
#
|
|
14
|
-
# @example
|
|
15
|
-
# signer = Remitmd::HttpSigner.new(url: "http://127.0.0.1:7402", token: "rmit_sk_...")
|
|
16
|
-
# wallet = Remitmd::RemitWallet.new(signer: signer, chain: "base")
|
|
17
|
-
#
|
|
18
|
-
class HttpSigner
|
|
19
|
-
include Signer
|
|
20
|
-
|
|
21
|
-
# Create an HttpSigner, fetching and caching the wallet address.
|
|
22
|
-
#
|
|
23
|
-
# @param url [String] signer server URL (e.g. "http://127.0.0.1:7402")
|
|
24
|
-
# @param token [String] bearer token for authentication
|
|
25
|
-
# @raise [RemitError] if the server is unreachable, returns an error, or returns no address
|
|
26
|
-
def initialize(url:, token:)
|
|
27
|
-
@url = url.chomp("/")
|
|
28
|
-
@token = token
|
|
29
|
-
@address = fetch_address
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Sign a 32-byte digest (raw binary bytes).
|
|
33
|
-
# Posts to /sign/digest with the hex-encoded digest.
|
|
34
|
-
# Returns a 0x-prefixed 65-byte hex signature.
|
|
35
|
-
#
|
|
36
|
-
# @param digest_bytes [String] 32-byte binary digest
|
|
37
|
-
# @return [String] 0x-prefixed 65-byte hex signature
|
|
38
|
-
# @raise [RemitError] on network, auth, policy, or server errors
|
|
39
|
-
def sign(digest_bytes)
|
|
40
|
-
hex = "0x#{digest_bytes.unpack1("H*")}"
|
|
41
|
-
uri = URI("#{@url}/sign/digest")
|
|
42
|
-
http = build_http(uri)
|
|
43
|
-
|
|
44
|
-
req = Net::HTTP::Post.new(uri.path)
|
|
45
|
-
req["Content-Type"] = "application/json"
|
|
46
|
-
req["Authorization"] = "Bearer #{@token}"
|
|
47
|
-
req.body = { digest: hex }.to_json
|
|
48
|
-
|
|
49
|
-
resp = begin
|
|
50
|
-
http.request(req)
|
|
51
|
-
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, SocketError => e
|
|
52
|
-
raise RemitError.new(
|
|
53
|
-
RemitError::NETWORK_ERROR,
|
|
54
|
-
"HttpSigner: cannot reach signer server at #{@url}: #{e.message}"
|
|
55
|
-
)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
handle_sign_response(resp)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# The cached Ethereum address (0x-prefixed).
|
|
62
|
-
# @return [String]
|
|
63
|
-
attr_reader :address
|
|
64
|
-
|
|
65
|
-
# Never expose the bearer token in inspect/to_s output.
|
|
66
|
-
def inspect
|
|
67
|
-
"#<Remitmd::HttpSigner address=#{@address}>"
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
alias to_s inspect
|
|
71
|
-
|
|
72
|
-
private
|
|
73
|
-
|
|
74
|
-
# Fetch the wallet address from GET /address during construction.
|
|
75
|
-
# @return [String] the 0x-prefixed Ethereum address
|
|
76
|
-
# @raise [RemitError] on any failure
|
|
77
|
-
def fetch_address
|
|
78
|
-
uri = URI("#{@url}/address")
|
|
79
|
-
http = build_http(uri)
|
|
80
|
-
|
|
81
|
-
req = Net::HTTP::Get.new(uri.path)
|
|
82
|
-
req["Authorization"] = "Bearer #{@token}"
|
|
83
|
-
|
|
84
|
-
resp = begin
|
|
85
|
-
http.request(req)
|
|
86
|
-
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, SocketError => e
|
|
87
|
-
raise RemitError.new(
|
|
88
|
-
RemitError::NETWORK_ERROR,
|
|
89
|
-
"HttpSigner: cannot reach signer server at #{@url}: #{e.message}"
|
|
90
|
-
)
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
status = resp.code.to_i
|
|
94
|
-
|
|
95
|
-
if status == 401
|
|
96
|
-
raise RemitError.new(
|
|
97
|
-
RemitError::UNAUTHORIZED,
|
|
98
|
-
"HttpSigner: unauthorized -- check your REMIT_SIGNER_TOKEN"
|
|
99
|
-
)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
unless (200..299).cover?(status)
|
|
103
|
-
raise RemitError.new(
|
|
104
|
-
RemitError::SERVER_ERROR,
|
|
105
|
-
"HttpSigner: GET /address failed (#{status})"
|
|
106
|
-
)
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
body = begin
|
|
110
|
-
JSON.parse(resp.body.to_s)
|
|
111
|
-
rescue JSON::ParserError
|
|
112
|
-
raise RemitError.new(
|
|
113
|
-
RemitError::SERVER_ERROR,
|
|
114
|
-
"HttpSigner: GET /address returned malformed JSON"
|
|
115
|
-
)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
addr = body["address"]
|
|
119
|
-
if addr.nil? || addr.to_s.empty?
|
|
120
|
-
raise RemitError.new(
|
|
121
|
-
RemitError::SERVER_ERROR,
|
|
122
|
-
"HttpSigner: GET /address returned no address"
|
|
123
|
-
)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
addr.to_s
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
# Handle the response from POST /sign/digest.
|
|
130
|
-
# @param resp [Net::HTTPResponse]
|
|
131
|
-
# @return [String] the 0x-prefixed hex signature
|
|
132
|
-
# @raise [RemitError] on any error
|
|
133
|
-
def handle_sign_response(resp)
|
|
134
|
-
status = resp.code.to_i
|
|
135
|
-
|
|
136
|
-
if status == 401
|
|
137
|
-
raise RemitError.new(
|
|
138
|
-
RemitError::UNAUTHORIZED,
|
|
139
|
-
"HttpSigner: unauthorized -- check your REMIT_SIGNER_TOKEN"
|
|
140
|
-
)
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
if status == 403
|
|
144
|
-
reason = begin
|
|
145
|
-
data = JSON.parse(resp.body.to_s)
|
|
146
|
-
data["reason"] || "unknown"
|
|
147
|
-
rescue JSON::ParserError
|
|
148
|
-
"unknown"
|
|
149
|
-
end
|
|
150
|
-
raise RemitError.new(
|
|
151
|
-
RemitError::UNAUTHORIZED,
|
|
152
|
-
"HttpSigner: policy denied -- #{reason}"
|
|
153
|
-
)
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
unless (200..299).cover?(status)
|
|
157
|
-
detail = begin
|
|
158
|
-
data = JSON.parse(resp.body.to_s)
|
|
159
|
-
data["reason"] || data["error"] || "server error"
|
|
160
|
-
rescue JSON::ParserError
|
|
161
|
-
"server error"
|
|
162
|
-
end
|
|
163
|
-
raise RemitError.new(
|
|
164
|
-
RemitError::SERVER_ERROR,
|
|
165
|
-
"HttpSigner: sign failed (#{status}): #{detail}"
|
|
166
|
-
)
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
body = begin
|
|
170
|
-
JSON.parse(resp.body.to_s)
|
|
171
|
-
rescue JSON::ParserError
|
|
172
|
-
raise RemitError.new(
|
|
173
|
-
RemitError::SERVER_ERROR,
|
|
174
|
-
"HttpSigner: POST /sign/digest returned malformed JSON"
|
|
175
|
-
)
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
sig = body["signature"]
|
|
179
|
-
if sig.nil? || sig.to_s.empty?
|
|
180
|
-
raise RemitError.new(
|
|
181
|
-
RemitError::SERVER_ERROR,
|
|
182
|
-
"HttpSigner: server returned no signature"
|
|
183
|
-
)
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
sig.to_s
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
# Build a Net::HTTP client for the given URI.
|
|
190
|
-
# @param uri [URI] the target URI
|
|
191
|
-
# @return [Net::HTTP]
|
|
192
|
-
def build_http(uri)
|
|
193
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
|
194
|
-
http.use_ssl = uri.scheme == "https"
|
|
195
|
-
http.open_timeout = 5
|
|
196
|
-
http.read_timeout = 10
|
|
197
|
-
http
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
end
|