virgil-sdk 4.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/README.md +134 -0
- data/Rakefile +9 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/dockefiles/Dockerfile-200 +25 -0
- data/dockefiles/Dockerfile-2110 +36 -0
- data/dockefiles/Dockerfile-220 +26 -0
- data/dockefiles/Dockerfile-226 +25 -0
- data/dockefiles/Dockerfile-233 +25 -0
- data/dockefiles/Dockerfile-240 +26 -0
- data/docker-compose.yml +107 -0
- data/lib/virgil/sdk.rb +10 -0
- data/lib/virgil/sdk/client.rb +47 -0
- data/lib/virgil/sdk/client/card.rb +142 -0
- data/lib/virgil/sdk/client/card_validator.rb +104 -0
- data/lib/virgil/sdk/client/http.rb +45 -0
- data/lib/virgil/sdk/client/http/base_connection.rb +112 -0
- data/lib/virgil/sdk/client/http/cards_service_connection.rb +113 -0
- data/lib/virgil/sdk/client/http/request.rb +63 -0
- data/lib/virgil/sdk/client/request_signer.rb +90 -0
- data/lib/virgil/sdk/client/requests.rb +50 -0
- data/lib/virgil/sdk/client/requests/confirm_identity_request.rb +67 -0
- data/lib/virgil/sdk/client/requests/create_card_request.rb +105 -0
- data/lib/virgil/sdk/client/requests/revoke_card_request.rb +85 -0
- data/lib/virgil/sdk/client/requests/signable_request.rb +142 -0
- data/lib/virgil/sdk/client/requests/verify_identity_request.rb +60 -0
- data/lib/virgil/sdk/client/search_criteria.rb +79 -0
- data/lib/virgil/sdk/client/signatures_base64.rb +25 -0
- data/lib/virgil/sdk/client/virgil_client.rb +425 -0
- data/lib/virgil/sdk/cryptography.rb +42 -0
- data/lib/virgil/sdk/cryptography/hashes.rb +44 -0
- data/lib/virgil/sdk/cryptography/hashes/fingerprint.rb +79 -0
- data/lib/virgil/sdk/cryptography/hashes/hash_algorithm.rb +91 -0
- data/lib/virgil/sdk/cryptography/keys.rb +48 -0
- data/lib/virgil/sdk/cryptography/keys/key_pair.rb +46 -0
- data/lib/virgil/sdk/cryptography/keys/key_pair_type.rb +108 -0
- data/lib/virgil/sdk/cryptography/keys/key_storage.rb +177 -0
- data/lib/virgil/sdk/cryptography/keys/private_key.rb +44 -0
- data/lib/virgil/sdk/cryptography/keys/public_key.rb +44 -0
- data/lib/virgil/sdk/cryptography/keys/storage_item.rb +63 -0
- data/lib/virgil/sdk/cryptography/virgil_crypto.rb +411 -0
- data/lib/virgil/sdk/high_level.rb +21 -0
- data/lib/virgil/sdk/high_level/virgil_api.rb +71 -0
- data/lib/virgil/sdk/high_level/virgil_app_credentials.rb +54 -0
- data/lib/virgil/sdk/high_level/virgil_buffer.rb +161 -0
- data/lib/virgil/sdk/high_level/virgil_card.rb +204 -0
- data/lib/virgil/sdk/high_level/virgil_card_manager.rb +294 -0
- data/lib/virgil/sdk/high_level/virgil_card_verifier_info.rb +49 -0
- data/lib/virgil/sdk/high_level/virgil_context.rb +69 -0
- data/lib/virgil/sdk/high_level/virgil_identity.rb +17 -0
- data/lib/virgil/sdk/high_level/virgil_identity/email_confirmation.rb +60 -0
- data/lib/virgil/sdk/high_level/virgil_identity/validation_token.rb +49 -0
- data/lib/virgil/sdk/high_level/virgil_identity/verification_attempt.rb +69 -0
- data/lib/virgil/sdk/high_level/virgil_identity/verification_options.rb +56 -0
- data/lib/virgil/sdk/high_level/virgil_key.rb +168 -0
- data/lib/virgil/sdk/high_level/virgil_key_manager.rb +97 -0
- data/lib/virgil/sdk/version.rb +5 -0
- data/virgil-sdk.gemspec +31 -0
- metadata +203 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
# Copyright (C) 2016 Virgil Security Inc.
|
2
|
+
#
|
3
|
+
# Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
|
4
|
+
#
|
5
|
+
# All rights reserved.
|
6
|
+
#
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions are
|
9
|
+
# met:
|
10
|
+
#
|
11
|
+
# (1) Redistributions of source code must retain the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer.
|
13
|
+
#
|
14
|
+
# (2) Redistributions in binary form must reproduce the above copyright
|
15
|
+
# notice, this list of conditions and the following disclaimer in
|
16
|
+
# the documentation and/or other materials provided with the
|
17
|
+
# distribution.
|
18
|
+
#
|
19
|
+
# (3) Neither the name of the copyright holder nor the names of its
|
20
|
+
# contributors may be used to endorse or promote products derived from
|
21
|
+
# this software without specific prior written permission.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
|
24
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
25
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
+
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
27
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
28
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
29
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
30
|
+
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
31
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
32
|
+
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
|
35
|
+
|
36
|
+
module Virgil
|
37
|
+
module SDK
|
38
|
+
module Client
|
39
|
+
module Requests
|
40
|
+
# Revoke card signable API request.
|
41
|
+
class RevokeCardRequest < SignableRequest
|
42
|
+
|
43
|
+
# Class containing possible revocation reasons.
|
44
|
+
class Reasons
|
45
|
+
Unspecified = 'unspecified'
|
46
|
+
Compromised = 'compromised'
|
47
|
+
end
|
48
|
+
|
49
|
+
attr_accessor :card_id, :reason
|
50
|
+
|
51
|
+
# Constructs new CreateCardRequest object
|
52
|
+
def initialize(attributes)
|
53
|
+
super()
|
54
|
+
self.card_id = attributes[:card_id]
|
55
|
+
self.reason = attributes[:reason] || Reasons::Unspecified
|
56
|
+
end
|
57
|
+
|
58
|
+
# Restores request from snapshot model.
|
59
|
+
#
|
60
|
+
# Args:
|
61
|
+
# snapshot_model: snapshot model dict
|
62
|
+
def restore_from_snapshot_model(snapshot_model)
|
63
|
+
self.card_id = snapshot_model['card_id']
|
64
|
+
self.reason = snapshot_model['revocation_reason']
|
65
|
+
end
|
66
|
+
|
67
|
+
def restore(validation_token)
|
68
|
+
@validation_token = validation_token
|
69
|
+
end
|
70
|
+
|
71
|
+
# Constructs snapshot model for exporting and signing.
|
72
|
+
#
|
73
|
+
# Returns:
|
74
|
+
# Dict containing snapshot data model used for card revocation request.
|
75
|
+
def snapshot_model
|
76
|
+
return {
|
77
|
+
'card_id': self.card_id,
|
78
|
+
'revocation_reason': self.reason,
|
79
|
+
}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# Copyright (C) 2016 Virgil Security Inc.
|
2
|
+
#
|
3
|
+
# Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
|
4
|
+
#
|
5
|
+
# All rights reserved.
|
6
|
+
#
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions are
|
9
|
+
# met:
|
10
|
+
#
|
11
|
+
# (1) Redistributions of source code must retain the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer.
|
13
|
+
#
|
14
|
+
# (2) Redistributions in binary form must reproduce the above copyright
|
15
|
+
# notice, this list of conditions and the following disclaimer in
|
16
|
+
# the documentation and/or other materials provided with the
|
17
|
+
# distribution.
|
18
|
+
#
|
19
|
+
# (3) Neither the name of the copyright holder nor the names of its
|
20
|
+
# contributors may be used to endorse or promote products derived from
|
21
|
+
# this software without specific prior written permission.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
|
24
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
25
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
+
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
27
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
28
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
29
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
30
|
+
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
31
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
32
|
+
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
|
35
|
+
require 'json'
|
36
|
+
require 'base64'
|
37
|
+
|
38
|
+
module Virgil
|
39
|
+
module SDK
|
40
|
+
module Client
|
41
|
+
module Requests
|
42
|
+
# Base class for all API requests.
|
43
|
+
class SignableRequest
|
44
|
+
extend SignaturesBase64
|
45
|
+
attr_reader :signatures, :snapshot, :validation_token
|
46
|
+
|
47
|
+
# protected :signatures=, :snapshot=
|
48
|
+
# attr_writer :snapshot
|
49
|
+
|
50
|
+
# Constructs new SignableRequest object
|
51
|
+
def initialize
|
52
|
+
@signatures = {}
|
53
|
+
end
|
54
|
+
|
55
|
+
# Constructs snapshot model for exporting and signing.
|
56
|
+
#
|
57
|
+
# Should be implemented in the derived classes.
|
58
|
+
#
|
59
|
+
# Raises:
|
60
|
+
# NotImplementedError
|
61
|
+
def snapshot_model
|
62
|
+
raise NotImplementedError.new
|
63
|
+
end
|
64
|
+
|
65
|
+
# Restores request from snapshot model.
|
66
|
+
#
|
67
|
+
# Should be implemented in the derived classes.
|
68
|
+
#
|
69
|
+
# Args:
|
70
|
+
# snapshot: snapshot model dict
|
71
|
+
#
|
72
|
+
# Raises:
|
73
|
+
# NotImplementedError
|
74
|
+
def restore_from_snapshot_model(snapshot)
|
75
|
+
raise NotImplementedError.new
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# Restores request from snapshot.
|
80
|
+
#
|
81
|
+
# Args:
|
82
|
+
# snapshot: Json-encoded snapshot request will be restored from.
|
83
|
+
# signatures: Request signatures.
|
84
|
+
def restore(snapshot, signatures, validation_token = nil)
|
85
|
+
@snapshot = snapshot
|
86
|
+
@signatures = signatures
|
87
|
+
@validation_token = validation_token
|
88
|
+
model = JSON.parse(Crypto::Bytes.new(snapshot).to_s)
|
89
|
+
restore_from_snapshot_model(model)
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
# Takes request data snapshot.
|
94
|
+
#
|
95
|
+
# Returns:
|
96
|
+
# Request snapshot bytes.
|
97
|
+
def take_snapshot
|
98
|
+
json_string = self.snapshot_model.to_json
|
99
|
+
Crypto::Bytes.from_string(json_string)
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# Exports request snapshot.
|
104
|
+
#
|
105
|
+
# Returns:
|
106
|
+
# base64-encoded json representation of the request model.
|
107
|
+
def export
|
108
|
+
json_string = self.request_model.to_json
|
109
|
+
Base64.strict_encode64(json_string)
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# Request data snapshot
|
114
|
+
def snapshot
|
115
|
+
@snapshot ||= self.take_snapshot
|
116
|
+
end
|
117
|
+
|
118
|
+
# Adds signature to request."""
|
119
|
+
def sign_with(fingerprint_id, signature)
|
120
|
+
@signatures[fingerprint_id] = signature
|
121
|
+
end
|
122
|
+
|
123
|
+
# Request model used for json representation.
|
124
|
+
def request_model
|
125
|
+
model = {
|
126
|
+
'content_snapshot': Base64.strict_encode64(snapshot.to_s),
|
127
|
+
'meta': {
|
128
|
+
'signs': signatures
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
if validation_token
|
133
|
+
model[:meta][:validation] = {'token': validation_token.value}
|
134
|
+
end
|
135
|
+
|
136
|
+
return model
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Copyright (C) 2016 Virgil Security Inc.
|
2
|
+
#
|
3
|
+
# Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
|
4
|
+
#
|
5
|
+
# All rights reserved.
|
6
|
+
#
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions are
|
9
|
+
# met:
|
10
|
+
#
|
11
|
+
# (1) Redistributions of source code must retain the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer.
|
13
|
+
#
|
14
|
+
# (2) Redistributions in binary form must reproduce the above copyright
|
15
|
+
# notice, this list of conditions and the following disclaimer in
|
16
|
+
# the documentation and/or other materials provided with the
|
17
|
+
# distribution.
|
18
|
+
#
|
19
|
+
# (3) Neither the name of the copyright holder nor the names of its
|
20
|
+
# contributors may be used to endorse or promote products derived from
|
21
|
+
# this software without specific prior written permission.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
|
24
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
25
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
+
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
27
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
28
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
29
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
30
|
+
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
31
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
32
|
+
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
|
35
|
+
|
36
|
+
module Virgil
|
37
|
+
module SDK
|
38
|
+
module Client
|
39
|
+
module Requests
|
40
|
+
class VerifyIdentityRequest
|
41
|
+
attr_accessor :identity, :identity_type
|
42
|
+
private :identity_type=, :identity=
|
43
|
+
|
44
|
+
def initialize(identity, identity_type)
|
45
|
+
self.identity_type = identity_type
|
46
|
+
self.identity = identity
|
47
|
+
end
|
48
|
+
|
49
|
+
# Request model used for json representation.
|
50
|
+
def request_model
|
51
|
+
return {
|
52
|
+
'type': identity_type,
|
53
|
+
'value': identity
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Copyright (C) 2016 Virgil Security Inc.
|
2
|
+
#
|
3
|
+
# Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
|
4
|
+
#
|
5
|
+
# All rights reserved.
|
6
|
+
#
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions are
|
9
|
+
# met:
|
10
|
+
#
|
11
|
+
# (1) Redistributions of source code must retain the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer.
|
13
|
+
#
|
14
|
+
# (2) Redistributions in binary form must reproduce the above copyright
|
15
|
+
# notice, this list of conditions and the following disclaimer in
|
16
|
+
# the documentation and/or other materials provided with the
|
17
|
+
# distribution.
|
18
|
+
#
|
19
|
+
# (3) Neither the name of the copyright holder nor the names of its
|
20
|
+
# contributors may be used to endorse or promote products derived from
|
21
|
+
# this software without specific prior written permission.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
|
24
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
25
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
+
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
27
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
28
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
29
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
30
|
+
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
31
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
32
|
+
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
|
35
|
+
module Virgil
|
36
|
+
module SDK
|
37
|
+
module Client
|
38
|
+
# Class holds criteria for searching Cards.
|
39
|
+
SearchCriteria = Struct.new(:identities, :identity_type, :scope) do
|
40
|
+
def initialize(identities, identity_type=nil, scope=nil)
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
# Create new search criteria for searching cards by identity.
|
45
|
+
#
|
46
|
+
# Args:
|
47
|
+
# identity: VirgilIdentity value.
|
48
|
+
#
|
49
|
+
# Returns:
|
50
|
+
# Search criteria with provided identity.
|
51
|
+
def self.by_identity(identity)
|
52
|
+
return self.by_identities([identity])
|
53
|
+
end
|
54
|
+
|
55
|
+
# Create new search criteria for searching cards by identities.
|
56
|
+
#
|
57
|
+
# Args:
|
58
|
+
# identities: Identities value.
|
59
|
+
#
|
60
|
+
# Returns:
|
61
|
+
# Search criteria with provided identities.
|
62
|
+
def self.by_identities(identities)
|
63
|
+
return new(identities, nil, Card::APPLICATION)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Create new search criteria for searching cards by application bundle.
|
67
|
+
#
|
68
|
+
# Args:
|
69
|
+
# bundle: Application bundle.
|
70
|
+
#
|
71
|
+
# Returns:
|
72
|
+
# Search criteria for searching by bundle.
|
73
|
+
def self.by_app_bundle(bundle)
|
74
|
+
return new([bundle], 'application', Card::GLOBAL)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Virgil
|
2
|
+
module SDK
|
3
|
+
module Client
|
4
|
+
module SignaturesBase64
|
5
|
+
|
6
|
+
def signatures_to_base64(signatures_bytes)
|
7
|
+
encoded_signatures = {}
|
8
|
+
signatures_bytes.each do |key, val|
|
9
|
+
encoded_signatures[key] = Base64.strict_encode64(Virgil::Crypto::Bytes.new(val).to_s) #TODO
|
10
|
+
end
|
11
|
+
encoded_signatures
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def signatures_from_base64(signatures_base64)
|
16
|
+
decoded_signatures = {}
|
17
|
+
signatures_base64.each do |key, val|
|
18
|
+
decoded_signatures[key] = Virgil::Crypto::Bytes.from_base64(val)
|
19
|
+
end
|
20
|
+
decoded_signatures
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,425 @@
|
|
1
|
+
# Copyright (C) 2016 Virgil Security Inc.
|
2
|
+
#
|
3
|
+
# Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
|
4
|
+
#
|
5
|
+
# All rights reserved.
|
6
|
+
#
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions are
|
9
|
+
# met:
|
10
|
+
#
|
11
|
+
# (1) Redistributions of source code must retain the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer.
|
13
|
+
#
|
14
|
+
# (2) Redistributions in binary form must reproduce the above copyright
|
15
|
+
# notice, this list of conditions and the following disclaimer in
|
16
|
+
# the documentation and/or other materials provided with the
|
17
|
+
# distribution.
|
18
|
+
#
|
19
|
+
# (3) Neither the name of the copyright holder nor the names of its
|
20
|
+
# contributors may be used to endorse or promote products derived from
|
21
|
+
# this software without specific prior written permission.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
|
24
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
25
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
+
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
27
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
28
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
29
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
30
|
+
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
31
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
32
|
+
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
|
35
|
+
module Virgil
|
36
|
+
module SDK
|
37
|
+
module Client
|
38
|
+
# Virgil API client
|
39
|
+
#
|
40
|
+
# Contains methods for searching and managing cards.
|
41
|
+
class VirgilClient
|
42
|
+
# Exception raised when card is not valid
|
43
|
+
class InvalidCardException < StandardError
|
44
|
+
attr_reader :invalid_cards
|
45
|
+
|
46
|
+
def initialize(invalid_cards)
|
47
|
+
@invalid_cards = invalid_cards
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s
|
51
|
+
"Cards #{@invalid_cards} are not valid"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_accessor :access_token, :cards_service_url, :identity_service_url,
|
56
|
+
:cards_read_only_service_url, :card_validator
|
57
|
+
|
58
|
+
# Constructs new VirgilClient object
|
59
|
+
def initialize(
|
60
|
+
access_token=nil,
|
61
|
+
cards_service_url=Card::SERVICE_URL,
|
62
|
+
cards_read_only_service_url=Card::READ_ONLY_SERVICE_URL,
|
63
|
+
identity_service_url=Virgil::SDK::VirgilIdentity::IDENTITY_SERVICE_URL
|
64
|
+
)
|
65
|
+
self.access_token = access_token
|
66
|
+
self.cards_service_url = cards_service_url
|
67
|
+
self.cards_read_only_service_url = cards_read_only_service_url
|
68
|
+
self.identity_service_url = identity_service_url
|
69
|
+
end
|
70
|
+
|
71
|
+
# Create published new card from given attributes.
|
72
|
+
#
|
73
|
+
# Args:
|
74
|
+
# identity: Created card identity.
|
75
|
+
# identity_type: Created card identity type.
|
76
|
+
# key_pair: Key pair of the created card.
|
77
|
+
# Public key is stored in the card, private key is used for request signing.
|
78
|
+
# app_id: Application identity for authority sign.
|
79
|
+
# app_key: Application key for authority sign.
|
80
|
+
#
|
81
|
+
# Returns:
|
82
|
+
# Created card from server response.
|
83
|
+
def create_card(identity, identity_type, key_pair, app_id, app_key)
|
84
|
+
request = Virgil::SDK::Client::Requests::CreateCardRequest.new(
|
85
|
+
identity: identity,
|
86
|
+
identity_type: identity_type,
|
87
|
+
scope: Client::Card::APPLICATION,
|
88
|
+
raw_public_key: self.crypto.export_public_key(key_pair.public_key)
|
89
|
+
)
|
90
|
+
self.request_signer.self_sign(request, key_pair.private_key)
|
91
|
+
self.request_signer.authority_sign(request, app_id, app_key)
|
92
|
+
|
93
|
+
return self.create_card_from_signed_request(request)
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# Create unpublished local card from given attributes.
|
98
|
+
#
|
99
|
+
# Args:
|
100
|
+
# identity: Created card identity.
|
101
|
+
# identity_type: Created card identity type.
|
102
|
+
# private_key: Private key of the created card.
|
103
|
+
# Public key is stored in the card, private key is used for request signing.
|
104
|
+
# app_id: Application identity for authority sign.
|
105
|
+
# app_key: Application key for authority sign.
|
106
|
+
# custom_data(optional): is an associative array that contains application specific
|
107
|
+
# parameters(under key :data) and information about the device
|
108
|
+
# on which the keypair was created(under key :device and :device_name).
|
109
|
+
# example: {data: {my_key1: "my_val1", my_key2: "my_val2"}, device: "iPhone6s", device_name: "Space grey one"}
|
110
|
+
#
|
111
|
+
# Returns:
|
112
|
+
# Created local card that is not published to Virgil Security services
|
113
|
+
def new_card(identity, identity_type, private_key, custom_data={})
|
114
|
+
data = custom_data[:data]
|
115
|
+
custom_data.delete(:data)
|
116
|
+
request = Virgil::SDK::Client::Requests::CreateCardRequest.new(
|
117
|
+
identity: identity,
|
118
|
+
identity_type: identity_type,
|
119
|
+
scope: Client::Card::APPLICATION,
|
120
|
+
raw_public_key: self.crypto.extract_public_key(private_key).value,
|
121
|
+
info: custom_data,
|
122
|
+
data: data
|
123
|
+
)
|
124
|
+
self.request_signer.self_sign(request, private_key)
|
125
|
+
|
126
|
+
return Client::Card.from_request_model(request.request_model)
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# Create unpublished global card from given attributes.
|
131
|
+
#
|
132
|
+
# Args:
|
133
|
+
# identity: Created card identity.
|
134
|
+
# identity_type: Created card identity type.
|
135
|
+
# private_key: Key pair of the created card.
|
136
|
+
# Public key is stored in the card, private key is used for request signing.
|
137
|
+
# custom_data(optional): is an associative array that contains application specific
|
138
|
+
# parameters(under key :data) and information about the device
|
139
|
+
# on which the keypair was created(under key :device and :device_name).
|
140
|
+
# example: {data: {my_key1: "my_val1", my_key2: "my_val2"}, device: "iPhone6s", device_name: "Space grey one"}
|
141
|
+
#
|
142
|
+
# Returns:
|
143
|
+
# Created global card that is not published to Virgil Security services
|
144
|
+
def new_global_card(identity, identity_type, private_key, custom_data={})
|
145
|
+
data = custom_data[:data]
|
146
|
+
custom_data.delete(:data)
|
147
|
+
request = Virgil::SDK::Client::Requests::CreateCardRequest.new(
|
148
|
+
identity: identity,
|
149
|
+
identity_type: identity_type,
|
150
|
+
scope: Client::Card::GLOBAL,
|
151
|
+
raw_public_key: self.crypto.extract_public_key(private_key).value,
|
152
|
+
info: custom_data,
|
153
|
+
data: data
|
154
|
+
)
|
155
|
+
self.request_signer.self_sign(request, private_key)
|
156
|
+
|
157
|
+
return Client::Card.from_request_model(request.request_model)
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
def sign_and_publish_card(card, app_id, app_key)
|
162
|
+
request = card.to_request
|
163
|
+
request_signer.authority_sign(
|
164
|
+
request,
|
165
|
+
app_id,
|
166
|
+
app_key
|
167
|
+
)
|
168
|
+
create_card_from_signed_request(request)
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
def publish_as_global_card(card)
|
173
|
+
request = card.to_request
|
174
|
+
create_card_from_signed_request(request)
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
# Create new card from signed creation request.
|
179
|
+
#
|
180
|
+
# Args:
|
181
|
+
# create_request: signed card creation request.
|
182
|
+
#
|
183
|
+
# Returns:
|
184
|
+
# Created card from server response.
|
185
|
+
#
|
186
|
+
# Raises:
|
187
|
+
# VirgilClient.InvalidCardException if client has validator
|
188
|
+
# and returned card signatures are not valid.
|
189
|
+
def create_card_from_signed_request(create_request)
|
190
|
+
http_request = Virgil::SDK::Client::HTTP::Request.new(
|
191
|
+
method: Virgil::SDK::Client::HTTP::Request::POST,
|
192
|
+
endpoint: "/#{Card::VRA_VERSION}/card",
|
193
|
+
body: create_request.request_model
|
194
|
+
)
|
195
|
+
raw_response = self.cards_connection.send_request(http_request)
|
196
|
+
card = Card.from_response(raw_response)
|
197
|
+
self.validate_cards([card]) if self.card_validator
|
198
|
+
card
|
199
|
+
end
|
200
|
+
|
201
|
+
def create_card_from_signed_request_async(create_request)
|
202
|
+
thread = Thread.new do
|
203
|
+
current = Thread.current
|
204
|
+
current[:card] = create_card_from_signed_request(create_request)
|
205
|
+
end
|
206
|
+
thread.join
|
207
|
+
thread[:card]
|
208
|
+
end
|
209
|
+
|
210
|
+
|
211
|
+
# Revoke card by id.
|
212
|
+
#
|
213
|
+
# Args:
|
214
|
+
# card_id: id of the revoked card.
|
215
|
+
# reason: card revocation reason.
|
216
|
+
# The possible values can be found in RevokeCardRequest::Reasons class.
|
217
|
+
# app_id: Application identity for authority sign.
|
218
|
+
# app_key: Application key for authority sign.
|
219
|
+
def revoke_card(
|
220
|
+
card_id,
|
221
|
+
app_id,
|
222
|
+
app_key,
|
223
|
+
reason=Requests::RevokeCardRequest::Reasons::Unspecified
|
224
|
+
)
|
225
|
+
request = Requests::RevokeCardRequest.new(
|
226
|
+
card_id: card_id,
|
227
|
+
reason: reason
|
228
|
+
)
|
229
|
+
self.request_signer.authority_sign(request, app_id, app_key)
|
230
|
+
|
231
|
+
self.revoke_card_from_signed_request(request)
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
def revoke_global_card(
|
236
|
+
card_id,
|
237
|
+
key_pair,
|
238
|
+
validation_token,
|
239
|
+
reason=Requests::RevokeCardRequest::Reasons::Unspecified
|
240
|
+
)
|
241
|
+
request = Requests::RevokeCardRequest.new(
|
242
|
+
card_id: card_id,
|
243
|
+
reason: reason
|
244
|
+
)
|
245
|
+
request.restore(validation_token)
|
246
|
+
self.request_signer.authority_sign(request, card_id, key_pair.private_key)
|
247
|
+
self.revoke_card_from_signed_request(request)
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
# Revoke card using signed revocation request.
|
252
|
+
#
|
253
|
+
# Args:
|
254
|
+
# revocation_request: signed card revocation request.
|
255
|
+
def revoke_card_from_signed_request(revocation_request)
|
256
|
+
http_request = Virgil::SDK::Client::HTTP::Request.new(
|
257
|
+
method: HTTP::Request::DELETE,
|
258
|
+
endpoint: "/#{Card::VRA_VERSION}/card/#{revocation_request.card_id}",
|
259
|
+
body: revocation_request.request_model
|
260
|
+
)
|
261
|
+
self.cards_connection.send_request(http_request)
|
262
|
+
end
|
263
|
+
|
264
|
+
def verify_identity(identity, identity_type)
|
265
|
+
verify_identity_request = Requests::VerifyIdentityRequest.new(identity, identity_type)
|
266
|
+
verify_identity_from_request(verify_identity_request)
|
267
|
+
end
|
268
|
+
|
269
|
+
def verify_identity_from_request(identity_request)
|
270
|
+
http_request = Virgil::SDK::Client::HTTP::Request.new(
|
271
|
+
method: HTTP::Request::POST,
|
272
|
+
endpoint: "/#{Card::VRA_VERSION}/verify",
|
273
|
+
body: identity_request.request_model
|
274
|
+
)
|
275
|
+
raw_response = self.identity_service_connection.send_request(http_request)
|
276
|
+
raw_response['action_id']
|
277
|
+
|
278
|
+
end
|
279
|
+
|
280
|
+
def confirm_identity(action_id, confirmation_code, time_to_live, count_to_live)
|
281
|
+
request = Requests::ConfirmIdentityRequest.new(confirmation_code, action_id, time_to_live, count_to_live)
|
282
|
+
confirm_identity_from_request(request)
|
283
|
+
end
|
284
|
+
|
285
|
+
def confirm_identity_from_request(confirm_request)
|
286
|
+
http_request = Virgil::SDK::Client::HTTP::Request.new(
|
287
|
+
method: HTTP::Request::POST,
|
288
|
+
endpoint: "/#{Card::VRA_VERSION}/confirm",
|
289
|
+
body: confirm_request.request_model
|
290
|
+
)
|
291
|
+
raw_response = self.identity_service_connection.send_request(http_request)
|
292
|
+
raw_response['validation_token']
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
# Get card by id.
|
297
|
+
#
|
298
|
+
# Args:
|
299
|
+
# card_id: id of the card to get.
|
300
|
+
#
|
301
|
+
# Returns:
|
302
|
+
# Found card from server response.
|
303
|
+
#
|
304
|
+
# Raises:
|
305
|
+
# VirgilClient::InvalidCardException if client has validator
|
306
|
+
# and retrieved card signatures are not valid.
|
307
|
+
def get_card(card_id)
|
308
|
+
# type: (str) -> Card
|
309
|
+
http_request = Virgil::SDK::Client::HTTP::Request.new(
|
310
|
+
method: HTTP::Request::GET,
|
311
|
+
endpoint: "/#{Card::VC_VERSION}/card/#{card_id}",
|
312
|
+
)
|
313
|
+
raw_response = self.read_cards_connection.send_request(http_request)
|
314
|
+
card = Card.from_response(raw_response)
|
315
|
+
self.validate_cards([card]) if self.card_validator
|
316
|
+
card
|
317
|
+
end
|
318
|
+
|
319
|
+
# Search cards by specified identities.
|
320
|
+
#
|
321
|
+
# Args:
|
322
|
+
# identities: identity values for search.
|
323
|
+
#
|
324
|
+
# Returns:
|
325
|
+
# Found cards from server response.
|
326
|
+
def search_cards_by_identities(*identities)
|
327
|
+
return self.search_cards_by_criteria(
|
328
|
+
SearchCriteria.by_identities(identities)
|
329
|
+
)
|
330
|
+
end
|
331
|
+
|
332
|
+
# Search cards by specified app bundle.
|
333
|
+
#
|
334
|
+
# Args:
|
335
|
+
# bundle: application bundle for search.
|
336
|
+
#
|
337
|
+
# Returns:
|
338
|
+
# Found cards from server response.
|
339
|
+
def search_cards_by_app_bundle(bundle)
|
340
|
+
return self.search_cards_by_criteria(
|
341
|
+
SearchCriteria.by_app_bundle(bundle)
|
342
|
+
)
|
343
|
+
end
|
344
|
+
|
345
|
+
# Search cards by specified search criteria.
|
346
|
+
#
|
347
|
+
# Args:
|
348
|
+
# search_criteria: constructed search criteria.
|
349
|
+
#
|
350
|
+
# Returns:
|
351
|
+
# Found cards from server response.
|
352
|
+
#
|
353
|
+
# Raises:
|
354
|
+
# VirgilClient.InvalidCardException if client has validator
|
355
|
+
# and cards are not valid.
|
356
|
+
def search_cards_by_criteria(search_criteria)
|
357
|
+
body = {identities: search_criteria.identities}
|
358
|
+
if search_criteria.identity_type
|
359
|
+
body[:identity_type] = search_criteria.identity_type
|
360
|
+
end
|
361
|
+
if search_criteria.scope == Card::GLOBAL
|
362
|
+
body[:scope] = Card::GLOBAL
|
363
|
+
end
|
364
|
+
http_request = Virgil::SDK::Client::HTTP::Request.new(
|
365
|
+
method: HTTP::Request::POST,
|
366
|
+
endpoint: "/#{Card::VC_VERSION}/card/actions/search",
|
367
|
+
body: body,
|
368
|
+
)
|
369
|
+
response = self.read_cards_connection.send_request(http_request)
|
370
|
+
cards = response.map { |card| Card.from_response(card) }
|
371
|
+
self.validate_cards(cards) if self.card_validator
|
372
|
+
return cards
|
373
|
+
end
|
374
|
+
|
375
|
+
# Validate cards signatures.
|
376
|
+
# Args:
|
377
|
+
# cards: list of cards to validate.
|
378
|
+
#
|
379
|
+
# Raises:
|
380
|
+
# VirgilClient::InvalidCardException if some cards are not valid.
|
381
|
+
def validate_cards(cards)
|
382
|
+
invalid_cards = cards.select { |card| !card_validator.is_valid?(card) }
|
383
|
+
if invalid_cards.any?
|
384
|
+
raise InvalidCardException.new(invalid_cards)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
# Cards service connection used for creating and revoking cards.
|
389
|
+
def cards_connection
|
390
|
+
@_cards_connection ||= HTTP::CardsServiceConnection.new(
|
391
|
+
self.access_token,
|
392
|
+
self.cards_service_url
|
393
|
+
)
|
394
|
+
end
|
395
|
+
|
396
|
+
# Cards service connection used for getting and searching cards.
|
397
|
+
def read_cards_connection
|
398
|
+
@_read_cards_connection = HTTP::CardsServiceConnection.new(
|
399
|
+
self.access_token,
|
400
|
+
self.cards_read_only_service_url
|
401
|
+
)
|
402
|
+
end
|
403
|
+
|
404
|
+
|
405
|
+
def identity_service_connection
|
406
|
+
@identity_service_connection = HTTP::CardsServiceConnection.new(
|
407
|
+
nil,
|
408
|
+
self.identity_service_url
|
409
|
+
)
|
410
|
+
|
411
|
+
end
|
412
|
+
|
413
|
+
# Request signer for signing constructed requests.
|
414
|
+
def request_signer
|
415
|
+
@_request_signer ||= RequestSigner.new(self.crypto)
|
416
|
+
end
|
417
|
+
|
418
|
+
# Crypto library wrapper.
|
419
|
+
def crypto
|
420
|
+
@_crypto ||= Virgil::SDK::Cryptography::VirgilCrypto.new
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|