ruby_universign 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.env.example +3 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +9 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +149 -0
- data/Rakefile +4 -0
- data/bin/console +23 -0
- data/bin/setup +7 -0
- data/lib/universign.rb +20 -0
- data/lib/universign/client.rb +32 -0
- data/lib/universign/configuration.rb +33 -0
- data/lib/universign/document.rb +116 -0
- data/lib/universign/error.rb +14 -0
- data/lib/universign/safeguard.rb +59 -0
- data/lib/universign/service/document.rb +45 -0
- data/lib/universign/service/transaction.rb +86 -0
- data/lib/universign/signature_field.rb +16 -0
- data/lib/universign/signer.rb +41 -0
- data/lib/universign/signer_infos.rb +56 -0
- data/lib/universign/transaction.rb +101 -0
- data/lib/universign/transaction_signer.rb +107 -0
- data/lib/universign/version.rb +3 -0
- data/ruby_universign.gemspec +36 -0
- metadata +176 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d1fa1af558c66f055f6fe0199c1733e6397f963c
|
4
|
+
data.tar.gz: c5b5525f439229fa8b4633bb804971324ba07481
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f81314ec97a5383cbc63eee709122508ec6c6af177c08f4359419f50499df4389f6b405576982aba02c6f9b5ee1553e28a8c756e5e401e039764ba39116afb3
|
7
|
+
data.tar.gz: 9cd5a8bf9c16232d8593304fed7e6ba098baf057646f02837bee5a78c61bbddfbd3fe175e0baae66f3158e9b2ea4f18e447832119a6da257960d34345554714d
|
data/.env.example
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 CapSens
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# RubyUniversign
|
2
|
+
|
3
|
+
RubyUniversign is a Ruby gem for interacting with [Universign](https://www.universign.com/) electronic signature API.
|
4
|
+
|
5
|
+
It ease requests to Universign API, documents uploads and following signature state.
|
6
|
+
|
7
|
+
This gem is **not** officialy made by Universign, but was originally created for [CapSens](https://capsens.eu/) internal usage.
|
8
|
+
|
9
|
+
This gem currently integrate electronic signature service, but not other Universign services (timestamping and server stamp).
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'ruby_universign', require: 'universign'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then run `bundle`
|
20
|
+
|
21
|
+
Or, #TODO
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
Configuration:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
# if you're using Rails, put this in an initializer
|
29
|
+
Universign.configure do |config|
|
30
|
+
config.endpoint = ENV['UNIVERSIGN_ENDPOINT']
|
31
|
+
config.login = ENV['UNIVERSIGN_LOGIN']
|
32
|
+
config.password = ENV['UNIVERSIGN_PASSWORD']
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
Then, you can create a transaction like this:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
document_from_url = Universign::Document.new(
|
40
|
+
name: 'my_contract.pdf',
|
41
|
+
url: 'http://www.orimi.com/pdf-test.pdf'
|
42
|
+
)
|
43
|
+
document_from_content = Universign::Document.new(
|
44
|
+
name: 'another.pdf',
|
45
|
+
content: File.open('spec/fixtures/universign-guide-8.8.pdf').read
|
46
|
+
)
|
47
|
+
|
48
|
+
signer = Universign::TransactionSigner.new(
|
49
|
+
first_name: "Signer's first name",
|
50
|
+
last_name: "Signer's last name",
|
51
|
+
email: 'test@gmail.com',
|
52
|
+
phone_number: '0101010101',
|
53
|
+
success_url: 'https://google.com/',
|
54
|
+
signature: Universign::SignatureField.new(coordinate: [20, 20], page: 1)
|
55
|
+
)
|
56
|
+
|
57
|
+
transaction = Universign::Transaction.create(
|
58
|
+
documents: [document_from_url, document_from_content],
|
59
|
+
signers: [signer],
|
60
|
+
options: { profile: 'default', final_doc_sent: true }
|
61
|
+
)
|
62
|
+
|
63
|
+
transaction.url
|
64
|
+
# => "https://sign.test.universign.eu/fr/signature/?id=f052e35e-a792-4440-bb67-6b5c3f17aa30"
|
65
|
+
|
66
|
+
transaction.transaction_id
|
67
|
+
# => "9696179e-a43d-4803-beeb-9e5c02fd159b"
|
68
|
+
|
69
|
+
# get back universign transaction:
|
70
|
+
transaction = Universign::Transaction.new('9696179e-a43d-4803-beeb-9e5c02fd159b')
|
71
|
+
transaction.signed?
|
72
|
+
|
73
|
+
```
|
74
|
+
|
75
|
+
### `Universign::Document`
|
76
|
+
|
77
|
+
It can be created with either your file's content or your file's url.
|
78
|
+
|
79
|
+
### `Universign::SignatureField`
|
80
|
+
|
81
|
+
Nothing much to say here. It follows Universign's signature field.
|
82
|
+
|
83
|
+
### `Universign::TransactionSigner`
|
84
|
+
|
85
|
+
* `success_url` is where your user will be redirected after signing the documents.
|
86
|
+
* `phone_number` is optional. If you don't specify it, Universign will ask the user for it at the time of the signature.
|
87
|
+
* `email` is optional, unless you want to use transaction's `final_doc_sent` option (to send signed documents to user's email).
|
88
|
+
|
89
|
+
### `Universign::Transaction`
|
90
|
+
|
91
|
+
To start a transaction with Universign, you only require documents and signers.
|
92
|
+
|
93
|
+
Options are, as the name imply, optional ! Available options are (snake_case of Universign's names):
|
94
|
+
|
95
|
+
```
|
96
|
+
custom_id
|
97
|
+
description
|
98
|
+
handwritten_signature_mode
|
99
|
+
certificate_type
|
100
|
+
language
|
101
|
+
identification_type
|
102
|
+
handwritten_signature
|
103
|
+
profile
|
104
|
+
final_doc_sent
|
105
|
+
final_doc_requester_sent
|
106
|
+
```
|
107
|
+
|
108
|
+
Default options are:
|
109
|
+
```ruby
|
110
|
+
{
|
111
|
+
handwrittenSignatureMode: 1,
|
112
|
+
identificationType: 'sms',
|
113
|
+
language: 'fr',
|
114
|
+
certificateType: 'simple'
|
115
|
+
}
|
116
|
+
```
|
117
|
+
|
118
|
+
For more informations on theses options, see Universign's official documentation
|
119
|
+
|
120
|
+
Once your transaction is created:
|
121
|
+
* `url` is where you must redirect your users for them to sign
|
122
|
+
* `transaction_id` is the id you must save to retrieve it later. You can request up-to-date informations from Universign with `Universign::Transaction.new(transaction_id)`.
|
123
|
+
* `signed?` returns a boolean that tells you if the transaction is signed, or not !
|
124
|
+
|
125
|
+
## Universign documentation
|
126
|
+
|
127
|
+
As of September 25th 2018, all official Universign documentation can be found at [https://help.universign.com/hc/fr/sections/360000148149-Guides-Universign]().
|
128
|
+
|
129
|
+
## Development
|
130
|
+
|
131
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
132
|
+
|
133
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
134
|
+
|
135
|
+
(# TODO) To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
136
|
+
|
137
|
+
## Contributing
|
138
|
+
|
139
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/CapSens/universign. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
140
|
+
|
141
|
+
## License
|
142
|
+
|
143
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
144
|
+
|
145
|
+
|
146
|
+
|
147
|
+
## notes
|
148
|
+
|
149
|
+
final_doc_sent: pour que le document soit envoyé par mail au signataire
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "universign"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
require 'dotenv'
|
13
|
+
|
14
|
+
Dotenv.load
|
15
|
+
|
16
|
+
Universign.configure do |config|
|
17
|
+
config.endpoint = ENV['UNIVERSIGN_ENDPOINT']
|
18
|
+
config.login = ENV['UNIVERSIGN_LOGIN']
|
19
|
+
config.password = ENV['UNIVERSIGN_PASSWORD']
|
20
|
+
end
|
21
|
+
|
22
|
+
require "irb"
|
23
|
+
IRB.start
|
data/bin/setup
ADDED
data/lib/universign.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
|
3
|
+
require "universign/version"
|
4
|
+
require 'xmlrpc/client'
|
5
|
+
require 'universign/service/document'
|
6
|
+
require 'universign/service/transaction'
|
7
|
+
require 'universign/safeguard'
|
8
|
+
require 'universign/signer'
|
9
|
+
require 'universign/transaction'
|
10
|
+
require 'universign/signature_field'
|
11
|
+
require 'universign/signer_infos'
|
12
|
+
require 'universign/transaction_signer'
|
13
|
+
require 'universign/client'
|
14
|
+
require 'universign/document'
|
15
|
+
require 'universign/configuration'
|
16
|
+
require 'universign/error'
|
17
|
+
|
18
|
+
module Universign
|
19
|
+
include Error
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Universign
|
4
|
+
class Client
|
5
|
+
include ::Singleton
|
6
|
+
attr_reader :client
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@client = XMLRPC::Client.new2(Universign.configuration.endpoint)
|
10
|
+
@client.user = Universign.configuration.login
|
11
|
+
@client.password = Universign.configuration.password
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(method, *args, &block)
|
15
|
+
if @client.respond_to?(method)
|
16
|
+
@client.send(method, *args, &block)
|
17
|
+
else
|
18
|
+
super(method, *args, &block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# _ _
|
23
|
+
# _____ _____ ___ _ __ | |_(_) ___ _ __ ___
|
24
|
+
# / _ \ \/ / __/ _ \ '_ \| __| |/ _ \| '_ \/ __|
|
25
|
+
# | __/> < (_| __/ |_) | |_| | (_) | | | \__ \
|
26
|
+
# \___/_/\_\___\___| .__/ \__|_|\___/|_| |_|___/
|
27
|
+
# |_|
|
28
|
+
class InvalidCredentials < StandardError; end
|
29
|
+
class ErrorWhenSigningPDF < StandardError; end
|
30
|
+
class UnknownException < StandardError; end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Universign
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :login, :password, :endpoint
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@login = ''
|
7
|
+
@password = ''
|
8
|
+
@endpoint = ''
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Universign::Configuration] Universign's current configuration
|
13
|
+
def self.configuration
|
14
|
+
@configuration ||= Configuration.new
|
15
|
+
end
|
16
|
+
|
17
|
+
# Set Universign's configuration
|
18
|
+
# @param config [Universign::Configuration]
|
19
|
+
def self.configuration=(config)
|
20
|
+
@configuration = config
|
21
|
+
end
|
22
|
+
|
23
|
+
# Modify Universign's current configuration
|
24
|
+
# @yieldparam [Universign::Configuration] config current Universign config
|
25
|
+
# ```
|
26
|
+
# Universign.configure do |config|
|
27
|
+
# config.login = "your-mail@provider.com"
|
28
|
+
# end
|
29
|
+
# ```
|
30
|
+
def self.configure
|
31
|
+
yield configuration
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Universign
|
2
|
+
class Document
|
3
|
+
include Universign::Safeguard
|
4
|
+
|
5
|
+
attr_reader :name, :file_content, :file_url
|
6
|
+
attr_accessor :params
|
7
|
+
|
8
|
+
# Create a new Universign::Document
|
9
|
+
#
|
10
|
+
# @param [Hash] options
|
11
|
+
# @option options [Array<Byte>] :content Content of the PDF
|
12
|
+
# @option options [String] :url URL of the PDF
|
13
|
+
# @option options [String] :name Name of the PDF
|
14
|
+
# @option options [Hash] :meta_data Hash to join to the PDF
|
15
|
+
def initialize(options = {})
|
16
|
+
@params = HashWithIndifferentAccess.new
|
17
|
+
|
18
|
+
options.each do |key, value|
|
19
|
+
send("#{key}=", value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Create a new document from a Hash
|
24
|
+
#
|
25
|
+
# @param [Hash] data
|
26
|
+
# @return [Universign::Document]
|
27
|
+
def self.from_data(data)
|
28
|
+
@params = data
|
29
|
+
|
30
|
+
document = Universign::Document.new
|
31
|
+
document.params.merge!(@params)
|
32
|
+
document
|
33
|
+
end
|
34
|
+
|
35
|
+
# The raw content of the PDF document
|
36
|
+
#
|
37
|
+
# @return [Array<Byte>]
|
38
|
+
def content
|
39
|
+
@content ||= params['content']
|
40
|
+
end
|
41
|
+
|
42
|
+
def content=(data)
|
43
|
+
@content = data
|
44
|
+
params[:content] = XMLRPC::Base64.new(data)
|
45
|
+
end
|
46
|
+
|
47
|
+
# The URL to download the PDF document
|
48
|
+
#
|
49
|
+
# @return [String]
|
50
|
+
def url
|
51
|
+
@url ||= params['url']
|
52
|
+
end
|
53
|
+
|
54
|
+
def url=(data)
|
55
|
+
@url = data
|
56
|
+
params['url'] = data
|
57
|
+
end
|
58
|
+
|
59
|
+
# The type of this document
|
60
|
+
#
|
61
|
+
# @return [String]
|
62
|
+
def document_type
|
63
|
+
@document_type ||= params['documentType']
|
64
|
+
end
|
65
|
+
|
66
|
+
# The file name of this document
|
67
|
+
#
|
68
|
+
# @return [String]
|
69
|
+
def name
|
70
|
+
@name ||= params['name']
|
71
|
+
end
|
72
|
+
|
73
|
+
def name=(data)
|
74
|
+
@name = data
|
75
|
+
params['name'] = data
|
76
|
+
end
|
77
|
+
|
78
|
+
# The meta data of the PDF document
|
79
|
+
#
|
80
|
+
# @return [Hash]
|
81
|
+
def meta_data
|
82
|
+
@meta_data ||= params['metaData']
|
83
|
+
end
|
84
|
+
|
85
|
+
def meta_data=(data)
|
86
|
+
if !data.is_a?(Hash)
|
87
|
+
raise MetaDataMustBeAHash
|
88
|
+
end
|
89
|
+
|
90
|
+
@meta_data = data
|
91
|
+
params['metaData'] = data
|
92
|
+
end
|
93
|
+
|
94
|
+
# _ _
|
95
|
+
# _____ _____ ___ _ __ | |_(_) ___ _ __ ___
|
96
|
+
# / _ \ \/ / __/ _ \ '_ \| __| |/ _ \| '_ \/ __|
|
97
|
+
# | __/> < (_| __/ |_) | |_| | (_) | | | \__ \
|
98
|
+
# \___/_/\_\___\___| .__/ \__|_|\___/|_| |_|___/
|
99
|
+
# |_|
|
100
|
+
class UnknownDocument < StandardError; end
|
101
|
+
class NotSigned < StandardError; end
|
102
|
+
class MissingDocument < StandardError; end
|
103
|
+
class MetaDataMustBeAHash < StandardError; end
|
104
|
+
class DocumentURLInvalid < StandardError
|
105
|
+
attr_accessor :url
|
106
|
+
|
107
|
+
def initialize(url)
|
108
|
+
@url = url
|
109
|
+
end
|
110
|
+
|
111
|
+
def to_s
|
112
|
+
"Can't find document at '#{@url}''"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Universign
|
2
|
+
module Error
|
3
|
+
autoload :Client, 'client'
|
4
|
+
ERROR_CODE = {
|
5
|
+
73002 => Universign::Client::ErrorWhenSigningPDF, # An error occured when signing the PDF document
|
6
|
+
73010 => Universign::Client::InvalidCredentials, # The login and/or password are invalid.
|
7
|
+
73025 => Universign::Document::UnknownDocument, # The used transaction id or custom id is invalid
|
8
|
+
73027 => Universign::Document::NotSigned
|
9
|
+
}
|
10
|
+
|
11
|
+
class UniversignError < StandardError; end
|
12
|
+
class NotEnoughTokens < UniversignError; end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Universign
|
2
|
+
module Safeguard
|
3
|
+
def self.included(klass)
|
4
|
+
klass.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
def safeguard(callback = nil, &block)
|
8
|
+
self.class.safeguard(callback, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def safeguard(callback = nil, &block)
|
13
|
+
block.call
|
14
|
+
rescue XMLRPC::FaultException => ex
|
15
|
+
if ex.faultCode == 73020
|
16
|
+
raise ex
|
17
|
+
end
|
18
|
+
|
19
|
+
known_exception = Universign::ERROR_CODE[ex.faultCode]
|
20
|
+
|
21
|
+
if known_exception
|
22
|
+
raise known_exception
|
23
|
+
elsif ex.faultString.include?('Error on document download for this URL')
|
24
|
+
url = ex.faultString.match(/<(.+)>/)[1] rescue 'unknown URL'
|
25
|
+
raise Universign::Document::DocumentURLInvalid.new(url)
|
26
|
+
elsif ex.faultString.include?('Invalid document URL')
|
27
|
+
url = ex.faultString.match(/<(.+)>/)[1] rescue 'unknown URL'
|
28
|
+
raise Universign::Document::DocumentURLInvalid.new(url)
|
29
|
+
elsif ex.faultString.include?('Not enough tokens')
|
30
|
+
raise Universign::NotEnoughTokens
|
31
|
+
elsif ex.faultString.include?('ID is unknown')
|
32
|
+
raise Universign::Document::UnknownDocument
|
33
|
+
else
|
34
|
+
handle_exception(ex, callback)
|
35
|
+
end
|
36
|
+
|
37
|
+
rescue RuntimeError => ex
|
38
|
+
if ex.message.include?('Authorization failed')
|
39
|
+
raise Universign::Client::InvalidCredentials
|
40
|
+
end
|
41
|
+
raise ex
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def handle_exception(ex, callback)
|
47
|
+
if callback.respond_to?(:call)
|
48
|
+
if callback.lambda? && callback.arity.zero?
|
49
|
+
callback.call
|
50
|
+
else
|
51
|
+
callback.call(ex)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
raise ex
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Universign
|
2
|
+
module Service
|
3
|
+
module Document
|
4
|
+
# Retrieve documents signed
|
5
|
+
#
|
6
|
+
# @return [Array<Universign::Document>]
|
7
|
+
def documents
|
8
|
+
@client = Universign::Client.instance
|
9
|
+
|
10
|
+
@documents ||= safeguard do
|
11
|
+
result = @client.call('requester.getDocuments', @transaction_id)
|
12
|
+
result.map do |document|
|
13
|
+
Universign::Document.from_data(document)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.included(base)
|
19
|
+
base.extend(ClassMethods)
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
attr_reader :documents
|
24
|
+
end
|
25
|
+
|
26
|
+
# def signed_with_transaction_id(transaction_id)
|
27
|
+
# @client = Universign::Client.new.client
|
28
|
+
#
|
29
|
+
# safeguard(-> { return false }) do
|
30
|
+
# result = @client.call('requester.getTransactionInfo', transaction_id)
|
31
|
+
# !result['signerInfos'].any? { |s| s['status'] != 'signed' }
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# def signed_with_custom_id(custom_id)
|
36
|
+
# @client = Universign::Client.new.client
|
37
|
+
#
|
38
|
+
# safeguard(-> { return false }) do
|
39
|
+
# result = @client.call('requester.getTransactionInfoByCustomId', custom_id)
|
40
|
+
# !result['signerInfos'].any? { |s| s['status'] != 'signed' }
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Universign
|
2
|
+
module Service
|
3
|
+
module Transaction
|
4
|
+
AVAILABLE_OPTIONS = {
|
5
|
+
custom_id: :customId,
|
6
|
+
description: :description,
|
7
|
+
handwritten_signature_mode: :handwrittenSignatureMode,
|
8
|
+
certificate_type: :certificateType,
|
9
|
+
language: :language,
|
10
|
+
identification_type: :identificationType,
|
11
|
+
handwritten_signature: :handwrittenSignature,
|
12
|
+
profile: :profile,
|
13
|
+
final_doc_sent: :finalDocSent,
|
14
|
+
final_doc_requester_sent: :finalDocRequesterSent
|
15
|
+
}
|
16
|
+
|
17
|
+
DEFAULT_OPTIONS = {
|
18
|
+
handwrittenSignatureMode: 1,
|
19
|
+
identificationType: 'sms',
|
20
|
+
language: 'fr',
|
21
|
+
certificateType: 'simple'
|
22
|
+
}
|
23
|
+
|
24
|
+
# Get a transaction from Universign
|
25
|
+
#
|
26
|
+
# @return [Universign::Transaction]
|
27
|
+
def get
|
28
|
+
@client = Universign::Client.instance
|
29
|
+
|
30
|
+
safeguard do
|
31
|
+
result = @client.call('requester.getTransactionInfo', @transaction_id)
|
32
|
+
self.from_data(result)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.included(base)
|
37
|
+
base.extend(ClassMethods)
|
38
|
+
end
|
39
|
+
|
40
|
+
module ClassMethods
|
41
|
+
# Signs a document
|
42
|
+
#
|
43
|
+
# @param [Array<Universign::Document>] documents Documents to sign
|
44
|
+
# @param [Array<Universign::SignerTransaction>] signers
|
45
|
+
# @param [Hash] options
|
46
|
+
# @option options: [String] :custom_id Custom ID of the document
|
47
|
+
# @option options: [String] :description Description of the signature
|
48
|
+
# @option options: [String] :handwritten_signature_mode Type of signature
|
49
|
+
# @option options: [String] :certificate_type Type of certificate
|
50
|
+
# @option options: [String] :language Document's language
|
51
|
+
# @option options: [String] :identification_type
|
52
|
+
# @option options: [Boolean] :handwritten_signature
|
53
|
+
# @option options: [String] :profile
|
54
|
+
# @option options: [Boolean] :final_doc_sent
|
55
|
+
# @option options: [Boolean] :final_doc_requester_sent
|
56
|
+
#
|
57
|
+
# @raise [ArgumentError] Raised if unknown_key passed in options
|
58
|
+
#
|
59
|
+
# @return [Universign::Transaction]
|
60
|
+
def create(documents:, signers:, options: {})
|
61
|
+
@client = Universign::Client.instance
|
62
|
+
|
63
|
+
sign_options = DEFAULT_OPTIONS.merge(
|
64
|
+
documents: documents.map(&:params),
|
65
|
+
signers: signers.map(&:params),
|
66
|
+
)
|
67
|
+
|
68
|
+
options.each do |key, value|
|
69
|
+
known_key = AVAILABLE_OPTIONS[key]
|
70
|
+
|
71
|
+
if known_key
|
72
|
+
sign_options[known_key] = value
|
73
|
+
else
|
74
|
+
raise "Unknown Key"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
safeguard do
|
79
|
+
result = @client.call("requester.requestTransaction", sign_options)
|
80
|
+
Universign::Transaction.new(result['id'], result['url'])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Universign
|
2
|
+
class Signer
|
3
|
+
attr_accessor :params
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@params = {}
|
7
|
+
|
8
|
+
options.each do |key, value|
|
9
|
+
send("#{key}=", value)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_data(data)
|
14
|
+
@params = data
|
15
|
+
end
|
16
|
+
|
17
|
+
# This signer’s firstname
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
def first_name
|
21
|
+
@first_name || params['firstName']
|
22
|
+
end
|
23
|
+
|
24
|
+
def first_name=(data)
|
25
|
+
@first_name = data
|
26
|
+
params[:firstname] = data
|
27
|
+
end
|
28
|
+
|
29
|
+
# This signer’s lastname
|
30
|
+
#
|
31
|
+
# @return [String]
|
32
|
+
def last_name
|
33
|
+
@last_name || params['lastName']
|
34
|
+
end
|
35
|
+
|
36
|
+
def last_name=(data)
|
37
|
+
@last_name = data
|
38
|
+
params[:lastname] = data
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Universign
|
2
|
+
class SignerInfos < Signer
|
3
|
+
# The status of the signer
|
4
|
+
#
|
5
|
+
# The existing statuses are:
|
6
|
+
#
|
7
|
+
# | Status | Description |
|
8
|
+
# |:--------------------:|:-------------------------------------------------------------------------------------------:|
|
9
|
+
# | `waiting` | The signer has not yet been invited to sign. Others signers must sign prior to this user |
|
10
|
+
# | `ready` | The signer has been invited to sign, but has not tried yet |
|
11
|
+
# | `accessed` | The signer has accessed the signature service |
|
12
|
+
# | `code-sent` | The signer agreed to sign and has been sent an OTP |
|
13
|
+
# | `signed` | The signer has successfully signed. |
|
14
|
+
# | `pending-validation` | The signer has successfully signed and is pending RA validation |
|
15
|
+
# | `canceled` | The signer refused to sign, or one of the previous signers canceled or failed its signature |
|
16
|
+
# | `failed` | An error occured during the signature. In this case, error is set |
|
17
|
+
def status
|
18
|
+
data['status']
|
19
|
+
end
|
20
|
+
|
21
|
+
# The error message in case status == `failed`
|
22
|
+
#
|
23
|
+
# @return [String]
|
24
|
+
def error
|
25
|
+
data['error']
|
26
|
+
end
|
27
|
+
|
28
|
+
# The URL of the signature page
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
def url
|
32
|
+
data['url']
|
33
|
+
end
|
34
|
+
|
35
|
+
# the action date
|
36
|
+
#
|
37
|
+
# @return [String]
|
38
|
+
def action_date
|
39
|
+
data['actionDate']
|
40
|
+
end
|
41
|
+
|
42
|
+
# List of refused docs indexes
|
43
|
+
#
|
44
|
+
# @return [Array<Integer>]
|
45
|
+
def refused_docs
|
46
|
+
data['refusedDocs']
|
47
|
+
end
|
48
|
+
|
49
|
+
# The signer’s email
|
50
|
+
#
|
51
|
+
# @return [String]
|
52
|
+
def email
|
53
|
+
data['email']
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Universign
|
2
|
+
class Transaction
|
3
|
+
include Universign::Safeguard
|
4
|
+
include Service::Transaction
|
5
|
+
include Service::Document
|
6
|
+
|
7
|
+
attr_reader :transaction_id, :url, :data
|
8
|
+
|
9
|
+
def initialize(transaction_id = nil, url = nil)
|
10
|
+
@transaction_id = transaction_id
|
11
|
+
@url = url
|
12
|
+
@data = {}
|
13
|
+
|
14
|
+
self.get
|
15
|
+
end
|
16
|
+
|
17
|
+
def from_data(data)
|
18
|
+
@data = data
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [String]
|
22
|
+
#
|
23
|
+
# The status of the transaction. The existing statuses are:
|
24
|
+
#
|
25
|
+
# | Status | Description |
|
26
|
+
# |-------------|--------------------------------------------------------------------------------------------------|
|
27
|
+
# | `ready` | Signers can connect and sign |
|
28
|
+
# | `expired` | The transaction has been requested more than 7 days ago. It will no more be available to signers |
|
29
|
+
# | `canceled` | A signer has canceled the transaction. Signers will no more be able to connect to the service |
|
30
|
+
# | `failed` | An error occured during a signature. The signers won’t be able to connect to the service |
|
31
|
+
# | `completed` | All signers have successfuly sign, the requester can retrieve the documents |
|
32
|
+
def status
|
33
|
+
data['status']
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Array<String>]
|
37
|
+
def url
|
38
|
+
@url ||= data['signerInfos'].map { |si| si['url'] }
|
39
|
+
end
|
40
|
+
|
41
|
+
# A list of bean containing information about the signers
|
42
|
+
# and their progression in the signature process
|
43
|
+
#
|
44
|
+
# @return [Array<Universign::Signer]
|
45
|
+
def signers
|
46
|
+
raise 'NotImplementedYet'
|
47
|
+
end
|
48
|
+
|
49
|
+
# A bean containing information about the requester of a
|
50
|
+
# transaction
|
51
|
+
# @return
|
52
|
+
def initiator
|
53
|
+
data['initiatorInfo']
|
54
|
+
end
|
55
|
+
|
56
|
+
# The index of current signer if the status of transaction
|
57
|
+
# is ready or who ended the transactions for other status
|
58
|
+
#
|
59
|
+
# @return [Integer]
|
60
|
+
def current_signer
|
61
|
+
data['currentSigner']
|
62
|
+
end
|
63
|
+
|
64
|
+
# The creation date or last relaunch date of this transaction
|
65
|
+
#
|
66
|
+
# @return [Date]
|
67
|
+
def created_at
|
68
|
+
data['creationDate'].to_date
|
69
|
+
end
|
70
|
+
|
71
|
+
# The description of the Transaction
|
72
|
+
#
|
73
|
+
# @return [String]
|
74
|
+
def description
|
75
|
+
data['description']
|
76
|
+
end
|
77
|
+
|
78
|
+
# Whether the transaction was requested with requesting handwritten signature
|
79
|
+
# for each signature field or not.
|
80
|
+
#
|
81
|
+
# @return [Boolean]
|
82
|
+
def each_field
|
83
|
+
data['eachField']
|
84
|
+
end
|
85
|
+
|
86
|
+
# Whether the transaction is signed... or not !
|
87
|
+
#
|
88
|
+
# @return [Boolean]
|
89
|
+
def signed?
|
90
|
+
status == 'completed'
|
91
|
+
end
|
92
|
+
|
93
|
+
########################
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def client
|
98
|
+
@client ||= Universign::Client.new.client
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Universign
|
2
|
+
class TransactionSigner < Signer
|
3
|
+
attr_accessor :phone_number, :signature, :callbacks
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
super(options)
|
7
|
+
|
8
|
+
options.each do |key, value|
|
9
|
+
send("#{key}=", value)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# This signer’s organization
|
14
|
+
#
|
15
|
+
# @params [String] data
|
16
|
+
def organization=(data)
|
17
|
+
@organization = data
|
18
|
+
params[:organisation] = data
|
19
|
+
end
|
20
|
+
|
21
|
+
# This signer’s e-mail address
|
22
|
+
#
|
23
|
+
# @params [String] data
|
24
|
+
def email=(data)
|
25
|
+
@email = data
|
26
|
+
params[:emailAddress] = data
|
27
|
+
end
|
28
|
+
|
29
|
+
# This signer’s mobile phone number that should be
|
30
|
+
# written in the international format
|
31
|
+
#
|
32
|
+
# Mandatory if the authentication by sms is activated
|
33
|
+
#
|
34
|
+
# @params [String] data
|
35
|
+
def phone_number=(data)
|
36
|
+
@phone_number = data
|
37
|
+
params[:phoneNum] = data
|
38
|
+
end
|
39
|
+
|
40
|
+
# The role of this transaction actor
|
41
|
+
#
|
42
|
+
# | Role | Description |
|
43
|
+
# |:----------:|:----------------------------------------------------------------------------------------:|
|
44
|
+
# | `signer` | (default) This actor is a signer and he will be able to view the documents and sign them |
|
45
|
+
# | `observer` | This actor is an observer and he will be able only to view the documents |
|
46
|
+
#
|
47
|
+
# @params [String] data
|
48
|
+
def role=(data)
|
49
|
+
@role = data
|
50
|
+
params[:role] = data
|
51
|
+
end
|
52
|
+
|
53
|
+
# A description of a visible PDF signature field. If none
|
54
|
+
# provided, no signature field will be produced on the
|
55
|
+
# signed document
|
56
|
+
#
|
57
|
+
# @params [Universign::SignatureField] data
|
58
|
+
def signature_field=(data)
|
59
|
+
if !data.instance_of?(Universign::SignatureField)
|
60
|
+
raise 'BadSignatureFieldType' # TODO: create custom Exception
|
61
|
+
end
|
62
|
+
|
63
|
+
@signature_field = data
|
64
|
+
params[:signatureField] = data.params
|
65
|
+
end
|
66
|
+
|
67
|
+
# This signer’s birth date. This is an option for the certified
|
68
|
+
# signature
|
69
|
+
#
|
70
|
+
# @params [Date] data
|
71
|
+
def birtdate=(data)
|
72
|
+
@birthdate = data
|
73
|
+
params[:birthDate] = data
|
74
|
+
end
|
75
|
+
|
76
|
+
# The url to where the signer will be redirected, after the signatures are completed.
|
77
|
+
# If it is null it takes the value of {Universign::Transaction#success_url}
|
78
|
+
# If it is also null, it takes the default Universign success URL
|
79
|
+
def success_url=(data)
|
80
|
+
@success_url = data
|
81
|
+
params[:successURL] = data
|
82
|
+
end
|
83
|
+
|
84
|
+
def cancel_url=(data)
|
85
|
+
@cancel_url = data
|
86
|
+
params[:cancelURL] = data
|
87
|
+
end
|
88
|
+
|
89
|
+
def fail_url=(data)
|
90
|
+
@fail_url = data
|
91
|
+
params[:failURL] = data
|
92
|
+
end
|
93
|
+
|
94
|
+
# Which authentication type will be used when a signer will attempt to sign.
|
95
|
+
#
|
96
|
+
# The available values are :
|
97
|
+
# | Type | Description |
|
98
|
+
# |:-------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
|
99
|
+
# | `none` | The signer won’t be asked an authentication code when signing |
|
100
|
+
# | `email` | The signer will be sent a authentication code by e-mail. Using this option implies that this signer has a valid email property set, otherwise, an exception is thrown |
|
101
|
+
# | `sms` | The signer will be sent a authentication code by sms. Using this option implies that this signer has a valid `phone_number` property set, in other cases, an exception is thrown |
|
102
|
+
def identification_type=(data)
|
103
|
+
@identification_type = data
|
104
|
+
params[:identificationType] = data
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'universign/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ruby_universign"
|
8
|
+
spec.version = Universign::VERSION
|
9
|
+
spec.authors = ["Nicolas Besnard", "Yassine Zenati", "Antoine Becquet"]
|
10
|
+
spec.email = ["besnard.nicolas@gmail.com", "yassine@capsens.eu", "antoine@capsens.eu"]
|
11
|
+
|
12
|
+
spec.summary = "Universign's API Wrapper"
|
13
|
+
spec.description = <<~EOF
|
14
|
+
Ruby gem for interacting with [Universign](https://www.universign.com/) electronic signature API.
|
15
|
+
It ease requests to Universign API, documents uploads and following signature state.
|
16
|
+
This gem is **not** officialy made by Universign, but was originally created for [CapSens](https://capsens.eu/) internal usage.
|
17
|
+
EOF
|
18
|
+
spec.homepage = "https://github.com/CapSens/universign"
|
19
|
+
spec.license = "MIT"
|
20
|
+
|
21
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
|
+
spec.bindir = "exe"
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.required_ruby_version = '>= 2.0'
|
27
|
+
|
28
|
+
spec.add_runtime_dependency 'activesupport', '>= 4.1'
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
31
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
32
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
33
|
+
spec.add_development_dependency "dotenv", "~> 2.0"
|
34
|
+
spec.add_development_dependency "webmock", "~> 3.0"
|
35
|
+
spec.add_development_dependency "vcr", "~> 4.0"
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_universign
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicolas Besnard
|
8
|
+
- Yassine Zenati
|
9
|
+
- Antoine Becquet
|
10
|
+
autorequire:
|
11
|
+
bindir: exe
|
12
|
+
cert_chain: []
|
13
|
+
date: 2018-09-26 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '4.1'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '4.1'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: bundler
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '1.10'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '1.10'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: rake
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '10.0'
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '10.0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: rspec
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '3.0'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '3.0'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: dotenv
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - "~>"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '2.0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - "~>"
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '2.0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: webmock
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - "~>"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '3.0'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - "~>"
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '3.0'
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: vcr
|
101
|
+
requirement: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - "~>"
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '4.0'
|
106
|
+
type: :development
|
107
|
+
prerelease: false
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - "~>"
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '4.0'
|
113
|
+
description: |
|
114
|
+
Ruby gem for interacting with [Universign](https://www.universign.com/) electronic signature API.
|
115
|
+
It ease requests to Universign API, documents uploads and following signature state.
|
116
|
+
This gem is **not** officialy made by Universign, but was originally created for [CapSens](https://capsens.eu/) internal usage.
|
117
|
+
email:
|
118
|
+
- besnard.nicolas@gmail.com
|
119
|
+
- yassine@capsens.eu
|
120
|
+
- antoine@capsens.eu
|
121
|
+
executables: []
|
122
|
+
extensions: []
|
123
|
+
extra_rdoc_files: []
|
124
|
+
files:
|
125
|
+
- ".env.example"
|
126
|
+
- ".gitignore"
|
127
|
+
- ".rspec"
|
128
|
+
- ".travis.yml"
|
129
|
+
- CHANGELOG.md
|
130
|
+
- CODE_OF_CONDUCT.md
|
131
|
+
- Gemfile
|
132
|
+
- LICENSE.txt
|
133
|
+
- README.md
|
134
|
+
- Rakefile
|
135
|
+
- bin/console
|
136
|
+
- bin/setup
|
137
|
+
- lib/universign.rb
|
138
|
+
- lib/universign/client.rb
|
139
|
+
- lib/universign/configuration.rb
|
140
|
+
- lib/universign/document.rb
|
141
|
+
- lib/universign/error.rb
|
142
|
+
- lib/universign/safeguard.rb
|
143
|
+
- lib/universign/service/document.rb
|
144
|
+
- lib/universign/service/transaction.rb
|
145
|
+
- lib/universign/signature_field.rb
|
146
|
+
- lib/universign/signer.rb
|
147
|
+
- lib/universign/signer_infos.rb
|
148
|
+
- lib/universign/transaction.rb
|
149
|
+
- lib/universign/transaction_signer.rb
|
150
|
+
- lib/universign/version.rb
|
151
|
+
- ruby_universign.gemspec
|
152
|
+
homepage: https://github.com/CapSens/universign
|
153
|
+
licenses:
|
154
|
+
- MIT
|
155
|
+
metadata: {}
|
156
|
+
post_install_message:
|
157
|
+
rdoc_options: []
|
158
|
+
require_paths:
|
159
|
+
- lib
|
160
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '2.0'
|
165
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '0'
|
170
|
+
requirements: []
|
171
|
+
rubyforge_project:
|
172
|
+
rubygems_version: 2.6.8
|
173
|
+
signing_key:
|
174
|
+
specification_version: 4
|
175
|
+
summary: Universign's API Wrapper
|
176
|
+
test_files: []
|