clicksign-ruby-sdk 0.1.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.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +535 -0
  3. data/lib/clicksign/client.rb +143 -0
  4. data/lib/clicksign/configuration.rb +29 -0
  5. data/lib/clicksign/error_handler.rb +56 -0
  6. data/lib/clicksign/errors.rb +53 -0
  7. data/lib/clicksign/instrumentation.rb +32 -0
  8. data/lib/clicksign/json_api/atomic_results_parser.rb +61 -0
  9. data/lib/clicksign/json_api/bulk_operations_client.rb +95 -0
  10. data/lib/clicksign/json_api/operations/bulk_requirement.rb +89 -0
  11. data/lib/clicksign/json_api/operations.rb +38 -0
  12. data/lib/clicksign/json_api/parser.rb +31 -0
  13. data/lib/clicksign/json_api/query_builder.rb +45 -0
  14. data/lib/clicksign/json_api/serializer.rb +14 -0
  15. data/lib/clicksign/resource.rb +263 -0
  16. data/lib/clicksign/resources/acceptance_term/whatsapp.rb +12 -0
  17. data/lib/clicksign/resources/access_control_list.rb +35 -0
  18. data/lib/clicksign/resources/auto_signature/term.rb +12 -0
  19. data/lib/clicksign/resources/envelope_bulk_creation.rb +9 -0
  20. data/lib/clicksign/resources/folder.rb +22 -0
  21. data/lib/clicksign/resources/group.rb +21 -0
  22. data/lib/clicksign/resources/membership.rb +21 -0
  23. data/lib/clicksign/resources/notarial/bulk_requirement.rb +67 -0
  24. data/lib/clicksign/resources/notarial/document.rb +40 -0
  25. data/lib/clicksign/resources/notarial/envelope.rb +80 -0
  26. data/lib/clicksign/resources/notarial/event.rb +20 -0
  27. data/lib/clicksign/resources/notarial/requirement.rb +63 -0
  28. data/lib/clicksign/resources/notarial/signature_watcher.rb +39 -0
  29. data/lib/clicksign/resources/notarial/signer.rb +56 -0
  30. data/lib/clicksign/resources/template.rb +13 -0
  31. data/lib/clicksign/resources/template_field.rb +9 -0
  32. data/lib/clicksign/resources/user.rb +15 -0
  33. data/lib/clicksign/resources/webhook.rb +9 -0
  34. data/lib/clicksign/services.rb +35 -0
  35. data/lib/clicksign/version.rb +5 -0
  36. data/lib/clicksign/webhook.rb +41 -0
  37. data/lib/clicksign.rb +73 -0
  38. metadata +81 -0
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Clicksign
4
+ module Resources
5
+ module Notarial
6
+ class SignatureWatcher < Clicksign::Resource
7
+ self.resource_type = 'signature_watchers'
8
+
9
+ def self.retrieve(id, envelope_id:)
10
+ raw = client.get("/envelopes/#{envelope_id}/signature_watchers/#{id}")
11
+ parsed = JsonApi::Parser.parse(raw)
12
+ build_instance(parsed[:data].first, parent_id: envelope_id)
13
+ end
14
+
15
+ def self.create(envelope_id:, **attributes)
16
+ raw = client.post(
17
+ "/envelopes/#{envelope_id}/signature_watchers",
18
+ body: JsonApi::Serializer.dump(type: resource_type, attributes: attributes),
19
+ )
20
+ parsed = JsonApi::Parser.parse(raw)
21
+ build_instance(parsed[:data].first, parent_id: envelope_id)
22
+ end
23
+
24
+ def base_path
25
+ "/envelopes/#{@_parent_id || envelope_id}/signature_watchers"
26
+ end
27
+
28
+ def update(**)
29
+ raise NotImplementedError,
30
+ 'SignatureWatcher does not support update (route: except: [:update])'
31
+ end
32
+
33
+ def envelope_id
34
+ @_parent_id || relationships.dig('envelope', 'data', 'id')
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Clicksign
4
+ module Resources
5
+ module Notarial
6
+ class Signer < Clicksign::Resource
7
+ self.resource_type = 'signers'
8
+
9
+ def self.retrieve(id, envelope_id:)
10
+ raw = client.get("/envelopes/#{envelope_id}/signers/#{id}")
11
+ parsed = JsonApi::Parser.parse(raw)
12
+ build_instance(parsed[:data].first, parent_id: envelope_id)
13
+ end
14
+
15
+ def self.create(envelope_id:, **attributes)
16
+ raw = client.post(
17
+ "/envelopes/#{envelope_id}/signers",
18
+ body: JsonApi::Serializer.dump(type: resource_type, attributes: attributes),
19
+ )
20
+ parsed = JsonApi::Parser.parse(raw)
21
+ build_instance(parsed[:data].first, parent_id: envelope_id)
22
+ end
23
+
24
+ def self.notify(id, envelope_id:, message: nil, **email_customization)
25
+ attributes = {}
26
+ attributes[:message] = message if message
27
+ unless email_customization.empty?
28
+ attributes[:email_customization] =
29
+ email_customization
30
+ end
31
+ body = { data: { type: 'notifications', attributes: attributes } }
32
+ client.post("/envelopes/#{envelope_id}/signers/#{id}/notifications", body: body)
33
+ nil
34
+ end
35
+
36
+ def notify(message: nil, **email_customization)
37
+ self.class.notify(@id, envelope_id: envelope_id, message: message,
38
+ **email_customization)
39
+ end
40
+
41
+ def update(**)
42
+ raise NotImplementedError,
43
+ 'Signer does not support update (route: except: [:update])'
44
+ end
45
+
46
+ def base_path
47
+ "/envelopes/#{@_parent_id || envelope_id}/signers"
48
+ end
49
+
50
+ def envelope_id
51
+ @_parent_id || relationships.dig('envelope', 'data', 'id')
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Clicksign
4
+ module Resources
5
+ class Template < Clicksign::Resource
6
+ self.resource_type = 'templates'
7
+
8
+ def self.list_template_fields(template_id)
9
+ nested_list(template_id, nested_type: 'template_fields', as: TemplateField)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Clicksign
4
+ module Resources
5
+ class TemplateField < Clicksign::Resource
6
+ self.resource_type = 'template_fields'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Clicksign
4
+ module Resources
5
+ class User < Clicksign::Resource
6
+ self.resource_type = 'users'
7
+
8
+ def self.me
9
+ raw = client.get('/users/me')
10
+ parsed = JsonApi::Parser.parse(raw)
11
+ build_instance(parsed[:data].first)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Clicksign
4
+ module Resources
5
+ class Webhook < Clicksign::Resource
6
+ self.resource_type = 'webhooks'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Clicksign
4
+ class Services
5
+ def initialize(api_key:, environment: :production, base_url: nil,
6
+ open_timeout: 2, read_timeout: 10, write_timeout: 10, max_retries: 0)
7
+ resolved_url = base_url || resolve_environment(environment)
8
+ @client = Client.new(
9
+ api_key: api_key,
10
+ base_url: resolved_url,
11
+ open_timeout: open_timeout,
12
+ read_timeout: read_timeout,
13
+ write_timeout: write_timeout,
14
+ max_retries: max_retries,
15
+ )
16
+ end
17
+
18
+ def use
19
+ previous = Thread.current[:clicksign_client]
20
+ Thread.current[:clicksign_client] = @client
21
+ yield
22
+ ensure
23
+ Thread.current[:clicksign_client] = previous
24
+ end
25
+
26
+ private
27
+
28
+ def resolve_environment(env)
29
+ Configuration::ENVIRONMENTS.fetch(env.to_sym) do
30
+ valid = Configuration::ENVIRONMENTS.keys.join(', ')
31
+ raise ArgumentError, "Unknown environment: #{env}. Valid: #{valid}"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Clicksign
4
+ VERSION = '0.1.1'
5
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+
5
+ module Clicksign
6
+ module Webhook
7
+ DIGEST = 'sha256'
8
+
9
+ # Raises WebhookSignatureError if the Content-HMAC header does not match.
10
+ def self.verify_signature!(payload, signature, secret:)
11
+ expected = compute_signature(payload, secret: secret)
12
+ raise WebhookSignatureError, 'Webhook signature mismatch' unless secure_compare?(
13
+ expected, signature
14
+ )
15
+
16
+ true
17
+ end
18
+
19
+ # Returns true/false instead of raising.
20
+ def self.verify_signature(payload, signature, secret:)
21
+ verify_signature!(payload, signature, secret: secret)
22
+ rescue WebhookSignatureError
23
+ false
24
+ end
25
+
26
+ # Computes the expected Content-HMAC value for a given payload and secret.
27
+ def self.compute_signature(payload, secret:)
28
+ "#{DIGEST}=#{OpenSSL::HMAC.hexdigest(DIGEST, secret, payload)}"
29
+ end
30
+
31
+ # Constant-time comparison to prevent timing attacks.
32
+ def self.secure_compare?(expected, actual)
33
+ digest_a = OpenSSL::Digest::SHA256.hexdigest(expected)
34
+ digest_b = OpenSSL::Digest::SHA256.hexdigest(actual)
35
+ result = 0
36
+ digest_a.bytes.zip(digest_b.bytes) { |x, y| result |= x ^ y }
37
+ result.zero?
38
+ end
39
+ private_class_method :secure_compare?
40
+ end
41
+ end
data/lib/clicksign.rb ADDED
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'uri'
6
+
7
+ require_relative 'clicksign/version'
8
+ require_relative 'clicksign/configuration'
9
+ require_relative 'clicksign/errors'
10
+ require_relative 'clicksign/error_handler'
11
+ require_relative 'clicksign/instrumentation'
12
+ require_relative 'clicksign/webhook'
13
+ require_relative 'clicksign/json_api/query_builder'
14
+ require_relative 'clicksign/json_api/serializer'
15
+ require_relative 'clicksign/json_api/parser'
16
+ require_relative 'clicksign/json_api/operations'
17
+ require_relative 'clicksign/json_api/operations/bulk_requirement'
18
+ require_relative 'clicksign/json_api/atomic_results_parser'
19
+ require_relative 'clicksign/client'
20
+ require_relative 'clicksign/json_api/bulk_operations_client'
21
+ require_relative 'clicksign/resource'
22
+ require_relative 'clicksign/services'
23
+
24
+ Dir[File.join(__dir__, 'clicksign', 'resources', '**', '*.rb')].each do |file|
25
+ require file
26
+ end
27
+
28
+ module Clicksign
29
+ class << self
30
+ # Must be called once at application startup, before any threads are spawned.
31
+ # Module-level memoisation (@client, @configuration) is not thread-safe for
32
+ # concurrent first-access; subsequent calls are safe once initialised.
33
+ def configure
34
+ yield configuration
35
+ end
36
+
37
+ def configuration
38
+ @configuration ||= Configuration.new
39
+ end
40
+
41
+ def client
42
+ @client ||= Client.new(
43
+ api_key: configuration.api_key,
44
+ base_url: configuration.base_url,
45
+ open_timeout: configuration.open_timeout,
46
+ read_timeout: configuration.read_timeout,
47
+ write_timeout: configuration.write_timeout,
48
+ max_retries: configuration.max_retries,
49
+ )
50
+ end
51
+
52
+ def bulk_operations_client
53
+ @bulk_operations_client ||= JsonApi::BulkOperationsClient.new(
54
+ api_key: configuration.api_key,
55
+ base_url: configuration.base_url,
56
+ open_timeout: configuration.open_timeout,
57
+ read_timeout: configuration.read_timeout,
58
+ write_timeout: configuration.write_timeout,
59
+ max_retries: configuration.max_retries,
60
+ )
61
+ end
62
+
63
+ def on_request(&block) = Instrumentation.on(:request, &block)
64
+ def on_retry(&block) = Instrumentation.on(:retry, &block)
65
+ def on_error(&block) = Instrumentation.on(:error, &block)
66
+
67
+ def reset!
68
+ @configuration = nil
69
+ @client = nil
70
+ @bulk_operations_client = nil
71
+ end
72
+ end
73
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clicksign-ruby-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Clicksign
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Official Ruby SDK for the Clicksign e-signature API (v3). Supports envelope
13
+ management, signing workflows and webhooks. JSON:API compliant, no runtime dependencies
14
+ beyond the Ruby stdlib.
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - README.md
20
+ - lib/clicksign.rb
21
+ - lib/clicksign/client.rb
22
+ - lib/clicksign/configuration.rb
23
+ - lib/clicksign/error_handler.rb
24
+ - lib/clicksign/errors.rb
25
+ - lib/clicksign/instrumentation.rb
26
+ - lib/clicksign/json_api/atomic_results_parser.rb
27
+ - lib/clicksign/json_api/bulk_operations_client.rb
28
+ - lib/clicksign/json_api/operations.rb
29
+ - lib/clicksign/json_api/operations/bulk_requirement.rb
30
+ - lib/clicksign/json_api/parser.rb
31
+ - lib/clicksign/json_api/query_builder.rb
32
+ - lib/clicksign/json_api/serializer.rb
33
+ - lib/clicksign/resource.rb
34
+ - lib/clicksign/resources/acceptance_term/whatsapp.rb
35
+ - lib/clicksign/resources/access_control_list.rb
36
+ - lib/clicksign/resources/auto_signature/term.rb
37
+ - lib/clicksign/resources/envelope_bulk_creation.rb
38
+ - lib/clicksign/resources/folder.rb
39
+ - lib/clicksign/resources/group.rb
40
+ - lib/clicksign/resources/membership.rb
41
+ - lib/clicksign/resources/notarial/bulk_requirement.rb
42
+ - lib/clicksign/resources/notarial/document.rb
43
+ - lib/clicksign/resources/notarial/envelope.rb
44
+ - lib/clicksign/resources/notarial/event.rb
45
+ - lib/clicksign/resources/notarial/requirement.rb
46
+ - lib/clicksign/resources/notarial/signature_watcher.rb
47
+ - lib/clicksign/resources/notarial/signer.rb
48
+ - lib/clicksign/resources/template.rb
49
+ - lib/clicksign/resources/template_field.rb
50
+ - lib/clicksign/resources/user.rb
51
+ - lib/clicksign/resources/webhook.rb
52
+ - lib/clicksign/services.rb
53
+ - lib/clicksign/version.rb
54
+ - lib/clicksign/webhook.rb
55
+ homepage: https://github.com/djosino/clicksign-ruby-sdk
56
+ licenses:
57
+ - MIT
58
+ metadata:
59
+ source_code_uri: https://github.com/djosino/clicksign-ruby-sdk
60
+ changelog_uri: https://github.com/djosino/clicksign-ruby-sdk/blob/main/CHANGELOG.md
61
+ bug_tracker_uri: https://github.com/djosino/clicksign-ruby-sdk/issues
62
+ documentation_uri: https://github.com/djosino/clicksign-ruby-sdk
63
+ rubygems_mfa_required: 'true'
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '3.0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubygems_version: 4.0.11
79
+ specification_version: 4
80
+ summary: Ruby SDK for the Clicksign API
81
+ test_files: []