sezame-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/sezame-sdk.rb +3 -0
- data/lib/sezame-sdk/client.rb +153 -0
- data/lib/sezame-sdk/response.rb +151 -0
- data/lib/sezame-sdk/sezamejsonclient.rb +18 -0
- data/lib/sezame-sdk/version.rb +3 -0
- metadata +82 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f6d57334987a3e68df5d3616469bec1077d1ceaf
|
4
|
+
data.tar.gz: aab37915e30af2a759b4dfba942bd5419c20b1bf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 728dd84fe737b122e96a38f183cefaaeb46cc8f1d047a17b355117bf20404552935748a47252734ac08c4a0ceac15816922e33e86e40a6ecf0bfcc3afa08c64b
|
7
|
+
data.tar.gz: ebeba0e1e1a63edda11a5103fbec4ec8e88abf1e2cafda52ecb7acee80ad798d31a6161ebb84206c5be7ca58edff53e938f3271beed12f1e39c975491c105ad0
|
data/lib/sezame-sdk.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require_relative 'sezamejsonclient'
|
3
|
+
require_relative 'response'
|
4
|
+
|
5
|
+
|
6
|
+
module Sezame
|
7
|
+
|
8
|
+
##
|
9
|
+
# base class for client requests.
|
10
|
+
class Client
|
11
|
+
attr_reader :http
|
12
|
+
|
13
|
+
# Expects a certificate string in pem format, the
|
14
|
+
# corresponding private key and an optional keypassword
|
15
|
+
def initialize(cert = nil, key = nil, keypassword = nil)
|
16
|
+
@http = SezameJSONClient.new
|
17
|
+
@http.connect_timeout = 10
|
18
|
+
|
19
|
+
@endpoint = 'https://hqfrontend-finprin.finprin.com/'
|
20
|
+
|
21
|
+
if cert != nil && key != nil
|
22
|
+
@http.ssl_config.client_cert = OpenSSL::X509::Certificate.new(cert)
|
23
|
+
@http.ssl_config.client_key = OpenSSL::PKey.read(key, keypassword)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# start the self-registration process by specifying
|
28
|
+
# a recovery e-mail entered during app installation
|
29
|
+
# and a name for your application
|
30
|
+
def register(email, name)
|
31
|
+
endpoint = @endpoint + 'client/register'
|
32
|
+
response = @http.post endpoint, {
|
33
|
+
:email => email,
|
34
|
+
:name => name
|
35
|
+
}
|
36
|
+
Sezame::Response::Register.new(response)
|
37
|
+
end
|
38
|
+
|
39
|
+
# helper function for building a csr
|
40
|
+
# pass the client code, obtained by the registration call
|
41
|
+
# add an e-mail address and additional x509 options
|
42
|
+
def makecsr(clientcode, email, x509 = {}, keylen = 2048)
|
43
|
+
options = {
|
44
|
+
:country => 'AT',
|
45
|
+
:state => 'Vienna',
|
46
|
+
:city => 'Vienna',
|
47
|
+
:organization => '-',
|
48
|
+
:department => '-',
|
49
|
+
:common_name => clientcode,
|
50
|
+
:email => email
|
51
|
+
}
|
52
|
+
options.merge!(x509)
|
53
|
+
|
54
|
+
key = OpenSSL::PKey::RSA.new(keylen)
|
55
|
+
csr = OpenSSL::X509::Request.new
|
56
|
+
csr.version = 0
|
57
|
+
csr.subject = OpenSSL::X509::Name.new([
|
58
|
+
['C', options[:country], OpenSSL::ASN1::PRINTABLESTRING],
|
59
|
+
['ST', options[:state], OpenSSL::ASN1::PRINTABLESTRING],
|
60
|
+
['L', options[:city], OpenSSL::ASN1::PRINTABLESTRING],
|
61
|
+
['O', options[:organization], OpenSSL::ASN1::UTF8STRING],
|
62
|
+
['OU', options[:department], OpenSSL::ASN1::UTF8STRING],
|
63
|
+
['CN', options[:common_name], OpenSSL::ASN1::UTF8STRING],
|
64
|
+
['emailAddress', options[:email], OpenSSL::ASN1::UTF8STRING]
|
65
|
+
])
|
66
|
+
csr.public_key = key.public_key
|
67
|
+
csr.sign(key, OpenSSL::Digest::SHA256.new)
|
68
|
+
|
69
|
+
{
|
70
|
+
:csr => csr.to_pem,
|
71
|
+
:key => key.to_pem
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
# let the csr signed by the hq server, pass the
|
76
|
+
# shared secret as optained by the register call
|
77
|
+
def sign(csr, sharedsecret)
|
78
|
+
endpoint = @endpoint + 'client/sign'
|
79
|
+
response = @http.post endpoint, {
|
80
|
+
:csr => csr,
|
81
|
+
:sharedsecret => sharedsecret
|
82
|
+
}
|
83
|
+
Sezame::Response::Sign.new(response)
|
84
|
+
end
|
85
|
+
|
86
|
+
# check the pairing status for the given username
|
87
|
+
def link_status(username)
|
88
|
+
endpoint = @endpoint + 'client/link/status'
|
89
|
+
response = @http.post endpoint, {
|
90
|
+
:username => username
|
91
|
+
}
|
92
|
+
response.content
|
93
|
+
end
|
94
|
+
|
95
|
+
# pair the given username with your application
|
96
|
+
def link(username)
|
97
|
+
endpoint = @endpoint + 'client/link'
|
98
|
+
response = @http.post endpoint, {
|
99
|
+
:username => username
|
100
|
+
}
|
101
|
+
ret = Sezame::Response::Link.new(response)
|
102
|
+
ret.username = username
|
103
|
+
ret
|
104
|
+
end
|
105
|
+
|
106
|
+
# remove the pairing for the given username
|
107
|
+
def link_delete(username)
|
108
|
+
endpoint = @endpoint + 'client/link'
|
109
|
+
response = @http.delete endpoint, {
|
110
|
+
:username => username
|
111
|
+
}
|
112
|
+
Sezame::Response::LinkDelete.new(response)
|
113
|
+
end
|
114
|
+
|
115
|
+
# submit an authentication request for the given username
|
116
|
+
# the message is displayed on the mobile app
|
117
|
+
# the timeout parameter defined the amount of seconds the requests is valid
|
118
|
+
# the type of request (auth or fraud)
|
119
|
+
# a callback url, results are posted to this url
|
120
|
+
# extra_params to be returned with the callback post
|
121
|
+
def authorize(username, message = nil, timeout = nil, type = 'auth', callback = nil, extra_params = nil)
|
122
|
+
endpoint = @endpoint + 'auth/login'
|
123
|
+
params = {
|
124
|
+
:username => username
|
125
|
+
}
|
126
|
+
|
127
|
+
params[:type] = type if type
|
128
|
+
params[:message] = message if message
|
129
|
+
params[:timeout] = timeout if timeout
|
130
|
+
params[:callback] = callback if callback
|
131
|
+
params[:params] = extra_params if extra_params
|
132
|
+
|
133
|
+
Sezame::Response::Auth.new(@http.post endpoint, params)
|
134
|
+
end
|
135
|
+
|
136
|
+
# inform the user about fraud attempts, like plaintext password logins
|
137
|
+
def fraud(username, message = nil, timeout = nil, callback = nil, extra_params = nil)
|
138
|
+
authorize(username, message, timeout, 'fraud', callback, extra_params)
|
139
|
+
end
|
140
|
+
|
141
|
+
# fetch the status of an authentication request
|
142
|
+
def status(auth_id)
|
143
|
+
endpoint = @endpoint + 'auth/status/' + auth_id
|
144
|
+
Sezame::Response::Status.new(@http.get endpoint)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# cancel the service
|
149
|
+
def cancel
|
150
|
+
endpoint = @endpoint + 'client/cancel'
|
151
|
+
Sezame::Response::Cancel.new(@http.get endpoint)
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'rqrcode'
|
2
|
+
|
3
|
+
module Sezame
|
4
|
+
|
5
|
+
# defines a set of response classes
|
6
|
+
# to get easily response values
|
7
|
+
module Response
|
8
|
+
|
9
|
+
# generic response, expects the response as returned by the httpclient
|
10
|
+
class Generic
|
11
|
+
attr_reader :response
|
12
|
+
attr_reader :data
|
13
|
+
|
14
|
+
def initialize(response)
|
15
|
+
@response = response
|
16
|
+
@data = response.content
|
17
|
+
end
|
18
|
+
|
19
|
+
def is_empty
|
20
|
+
[201, 204, 304].include? @response.status
|
21
|
+
end
|
22
|
+
|
23
|
+
def is_ok
|
24
|
+
@response.status == 200
|
25
|
+
end
|
26
|
+
|
27
|
+
def is_notfound
|
28
|
+
@response.status == 404
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_status
|
32
|
+
unless @data.has_key?('status')
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
|
36
|
+
@data['status']
|
37
|
+
end
|
38
|
+
|
39
|
+
# get the error message return by hq if any
|
40
|
+
def get_message
|
41
|
+
unless @data.has_key?('message')
|
42
|
+
return nil
|
43
|
+
end
|
44
|
+
|
45
|
+
@data['message']
|
46
|
+
end
|
47
|
+
|
48
|
+
# return an array of error messages
|
49
|
+
def get_errors
|
50
|
+
unless @data.has_key?('errors')
|
51
|
+
return []
|
52
|
+
end
|
53
|
+
|
54
|
+
@data['errors']
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# represents the registration response
|
59
|
+
# returns the clientcode and the shared secret
|
60
|
+
class Register < Generic
|
61
|
+
def is_ok
|
62
|
+
super && @data.has_key?('clientcode')
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_clientcode
|
66
|
+
@data['clientcode']
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_sharedsecret
|
70
|
+
@data['sharedsecret']
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# represents the sign response
|
75
|
+
# returns the certificate
|
76
|
+
class Sign < Generic
|
77
|
+
def is_ok
|
78
|
+
super && @data.has_key?('cert')
|
79
|
+
end
|
80
|
+
|
81
|
+
def get_cert
|
82
|
+
@data['cert']
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# represents an authentication response
|
87
|
+
# returns the authentication id
|
88
|
+
class Auth < Generic
|
89
|
+
def is_ok
|
90
|
+
get_status == 'initiated'
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_id
|
94
|
+
@data['id']
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# auth status response
|
99
|
+
# returns the status of the authentication request
|
100
|
+
class Status < Generic
|
101
|
+
def is_authorized
|
102
|
+
get_status == 'authorized'
|
103
|
+
end
|
104
|
+
|
105
|
+
def is_denied
|
106
|
+
get_status == 'denied'
|
107
|
+
end
|
108
|
+
|
109
|
+
def is_pending
|
110
|
+
get_status == 'initiated'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# represents the pairing response
|
115
|
+
# returns a qrcode
|
116
|
+
class Link < Generic
|
117
|
+
attr_accessor :username
|
118
|
+
|
119
|
+
def is_ok
|
120
|
+
super && @data.has_key?('id')
|
121
|
+
end
|
122
|
+
|
123
|
+
def qrcode
|
124
|
+
linkdata = @data
|
125
|
+
linkdata[:username] = username
|
126
|
+
RQRCode::QRCode.new(linkdata.to_json)
|
127
|
+
end
|
128
|
+
|
129
|
+
def is_duplicate
|
130
|
+
@response.status == 409
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# remove pairing response
|
135
|
+
class LinkDelete < Generic
|
136
|
+
|
137
|
+
def is_ok
|
138
|
+
super || @response.status == 204
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# cancel service response
|
143
|
+
class Cancel < Generic
|
144
|
+
|
145
|
+
def is_ok
|
146
|
+
super || @response.status == 204
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'jsonclient'
|
2
|
+
|
3
|
+
# parse json in quirks mode, so that JSON fragments (true, false, simple strings) can be handled
|
4
|
+
class SezameJSONClient < JSONClient
|
5
|
+
|
6
|
+
def delete(uri, *args, &block)
|
7
|
+
request(:delete, uri, argument_to_hash_for_json(args), &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def wrap_json_response(original)
|
13
|
+
res = ::HTTP::Message.new_response(JSON.parse(original.content, :quirks_mode => true))
|
14
|
+
res.http_header = original.http_header
|
15
|
+
res.previous = original
|
16
|
+
res
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sezame-sdk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Finpin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rqrcode
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: httpclient
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.7'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.7'
|
41
|
+
description: |
|
42
|
+
Passwordless multi-factor authentication.
|
43
|
+
|
44
|
+
Unlike password-based solutions that require you to remember just another PIN or password,
|
45
|
+
sezame is a secure and simple multi-factor authentication solution.
|
46
|
+
You only need the username and your fingerprint on your smartphone to log into any sezame-enabled site.
|
47
|
+
email:
|
48
|
+
- office@finpintech.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- lib/sezame-sdk.rb
|
54
|
+
- lib/sezame-sdk/client.rb
|
55
|
+
- lib/sezame-sdk/response.rb
|
56
|
+
- lib/sezame-sdk/sezamejsonclient.rb
|
57
|
+
- lib/sezame-sdk/version.rb
|
58
|
+
homepage: https://www.seza.me/
|
59
|
+
licenses:
|
60
|
+
- BSD
|
61
|
+
metadata: {}
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
requirements: []
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 2.2.2
|
79
|
+
signing_key:
|
80
|
+
specification_version: 4
|
81
|
+
summary: Sezame ruby SDK
|
82
|
+
test_files: []
|