thisdata 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1bd194d89f48c0774d981d4c093ef12a1ed1b16e
4
+ data.tar.gz: 39ea8f55aaa501587e46cdb586e41a29f711760c
5
+ SHA512:
6
+ metadata.gz: 0f9c4c7388e0b80d34e78f798fc5691b4db3f864e7ca84db4ddd11499b1395cd76eb33ea3fcc4ff2a4faaa2e48ac428e877e99fabe63a3d2aa84fb53329488ec
7
+ data.tar.gz: fe572684f6b1790d900ee21fe12ba508c19b017196c621b7de68b1dc99ed1cb3bf7f3e4d9106ee8eddb9cc33ca2346bad2f9688b9b992a4b9f69de4872f4807b
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ /.bundle/
2
+ /Gemfile.lock
3
+ /tmp/
4
+ .DS_Store
5
+ *.gem
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ # 0.1.0
2
+
3
+ Initial release.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in this_data.gemspec
4
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 ThisData Ltd.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # ThisData Ruby
2
+
3
+ This gem allows you to use the ThisData Login Intelligence API.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'thisdata'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install thisdata
20
+
21
+ ## Usage
22
+
23
+ Run:
24
+
25
+ rails g this_data:install YOUR_API_KEY_HERE
26
+
27
+ You can find your API key by going to [ThisData](https://thisdata.com) >
28
+ Integrations > Login Intelligence API.
29
+
30
+ The generator will create a file in `config/initializers` called "this_data.rb".
31
+ If you need to do any further configuration or customization of ThisData,
32
+ that's the place to do it!
33
+
34
+ ## Ruby
35
+
36
+ You can track any event by calling `ThisData.track` and passing a Hash which
37
+ contains an event. See examples and required fields on our API documentation:
38
+ http://help.thisdata.com/docs/apiv1events
39
+
40
+ ## Rails
41
+
42
+ The ThisData::TrackRequest module can be included in a ActionController, giving
43
+ you a handy way to track requests.
44
+
45
+ e.g. in `app/controllers/application_controller.rb`
46
+ ```
47
+ class ApplicationController < ActionController::Base
48
+ include ThisData::TrackRequest
49
+
50
+ ...
51
+ end
52
+ ```
53
+
54
+ and in your sessions controller:
55
+ ```
56
+ class SessionsController < ApplicationController
57
+
58
+ def finalize
59
+ if login_was_valid?
60
+ # do login stuff
61
+ thisdata_track
62
+ else
63
+ thisdata_track('login-denied')
64
+ end
65
+ end
66
+
67
+ end
68
+ ```
69
+
70
+
71
+
72
+ ## Development
73
+
74
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
75
+
76
+ To install this gem onto your local machine, run `bundle exec rake install`. 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).
77
+
78
+ ## Contributing
79
+
80
+ Bug reports and pull requests are welcome on GitHub at https://github.com/revertio/thisdata-ruby.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "this_data"
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
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,30 @@
1
+ module ThisData
2
+ class InstallGenerator < Rails::Generators::Base
3
+
4
+ argument :api_key
5
+
6
+ desc "This generator creates a configuration file for the ThisData ruby client inside config/initializers"
7
+ def create_configuration_file
8
+ initializer "this_data.rb" do
9
+ <<-EOS
10
+ ThisData.setup do |config|
11
+ config.api_key = "#{api_key}"
12
+
13
+ # user_method will be called on a controller when using TrackRequest
14
+ # config.user_method = :current_user
15
+
16
+ # The following methods will be called on the object returned by user_method,
17
+ # to capture details about the user
18
+ # config.user_id_method = :id
19
+ # config.user_name_method = :name
20
+ # config.user_email_method = :email
21
+ # config.user_mobile_method = :mobile
22
+
23
+ # Define a Logger instance if you want to debug / track errors
24
+ # config.logger = Rails.logger unless Rails.env.production?
25
+ end
26
+ EOS
27
+ end
28
+ end
29
+ end
30
+ end
data/lib/this_data.rb ADDED
@@ -0,0 +1,71 @@
1
+ require "httparty"
2
+ require "logger"
3
+ require "json"
4
+
5
+ require "this_data/version"
6
+ require "this_data/verbs"
7
+ require "this_data/client"
8
+ require "this_data/configuration"
9
+ require "this_data/track_request"
10
+
11
+ module ThisData
12
+
13
+ class << self
14
+
15
+ # Configuration Object (instance of ThisData::Configuration)
16
+ attr_writer :configuration
17
+
18
+ def setup
19
+ yield(configuration)
20
+ end
21
+
22
+ def configuration
23
+ @configuration ||= ThisData::Configuration.new
24
+ end
25
+
26
+ def default_configuration
27
+ configuration.defaults
28
+ end
29
+
30
+ # Creates a Client and tracks an event.
31
+ # Event must be a Hash
32
+ def track(event)
33
+ Client.new.track(event)
34
+ log("Tracked event!")
35
+ rescue => e
36
+ ThisData.error("Failed to track event:")
37
+ ThisData.error(e)
38
+ e.backtrace.each do |line|
39
+ ThisData.error(line, prefix: false)
40
+ end
41
+ false
42
+ end
43
+
44
+ # A helper method to track a log-in event. Validates that the minimum
45
+ # required data is present.
46
+ def track_login(ip: '', user: {}, user_agent: nil)
47
+ raise ArgumentError, "IP Address is required" unless ip.length
48
+ raise ArgumentError, "User needs ID value" unless user[:id].to_s.length
49
+ track({
50
+ verb: ThisData::Verbs::LOG_IN,
51
+ ip: ip,
52
+ user_agent: user_agent,
53
+ user: user
54
+ })
55
+ end
56
+
57
+ def log(message, level: 'info', prefix: true)
58
+ if prefix
59
+ message = "[ThisData] " + message.to_s
60
+ end
61
+ configuration.logger.send(level, message) if configuration.logger
62
+ end
63
+ def warn(message, prefix: true)
64
+ log(message, level: 'warn', prefix: prefix)
65
+ end
66
+ def error(message, prefix: true)
67
+ log(message, level: 'error', prefix: prefix)
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,59 @@
1
+ module ThisData
2
+ # For the ThisData REST APIv1
3
+ # http://help.thisdata.com/docs/apiv1events
4
+ class Client
5
+
6
+ USER_AGENT = "ThisData Ruby v#{ThisData::VERSION}"
7
+ NO_API_KEY_MESSAGE = "Oops: you've got no ThisData API Key configured, so we can't send events. Specify your ThisData API key using ThisData#setup (find yours at https://thisdata.com)"
8
+
9
+ include HTTParty
10
+
11
+ base_uri "https://api.thisdata.com/v1/"
12
+
13
+ def initialize
14
+ @api_key = require_api_key
15
+ @headers = {
16
+ "User-Agent" => USER_AGENT
17
+ }
18
+ end
19
+
20
+ def require_api_key
21
+ ThisData.configuration.api_key || print_api_key_warning
22
+ end
23
+
24
+ # Tracks a user initiated event which has occurred within your app, e.g.
25
+ # a user logging in.
26
+ # See http://help.thisdata.com/v1.0/docs/apiv1events for more information.
27
+ # - event (Required: Hash) the event, containing the following keys:
28
+ # - verb (Required: String) 'what' the user did, e.g. 'log-in'.
29
+ # See ThisData::Verbs for predefined options.
30
+ # - ip (Required: String) the IP address of the request
31
+ # - user_agent (Optional: String) the user agent from the request
32
+ # - user (Required: Hash)
33
+ # - id (Required: String) a unique identifier for this User
34
+ # - email (Optional*: String) the user's email address.
35
+ # - mobile (Optional*: String) a mobile phone number in E.164 format
36
+ # *email and/or mobile MUST be passed if you want ThisData
37
+ # to send 'Was This You?' notifications via email and/or SMS
38
+ # - name (Optional: String) the user's name, used in notifications
39
+ def track(event)
40
+ post_event(event)
41
+ end
42
+
43
+ private
44
+
45
+ def version
46
+ ThisData.configuration.version
47
+ end
48
+
49
+ def post_event(payload_hash)
50
+ path_with_key = "/events?api_key=#{ThisData.configuration.api_key}"
51
+ self.class.post(path_with_key, headers: @headers, body: JSON.generate(payload_hash))
52
+ end
53
+
54
+ def print_api_key_warning
55
+ $stderr.puts(NO_API_KEY_MESSAGE)
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,75 @@
1
+ require "ostruct"
2
+
3
+ module ThisData
4
+ class Configuration
5
+
6
+ # Programatically create attr accessors for config_option
7
+ def self.config_option(name)
8
+ define_method(name) do
9
+ read_value(name)
10
+ end
11
+
12
+ define_method("#{name}=") do |value|
13
+ set_value(name, value)
14
+ end
15
+ end
16
+
17
+ # Your ThisData API Key - this can be found on ThisData.com > Integrations
18
+ # > Login Intelligence API
19
+ config_option :api_key
20
+
21
+ # Log the events sent
22
+ config_option :logger
23
+
24
+ # TrackRequest config options
25
+ # We will attempt to call this method on a Controller to get the user record
26
+ # Default: :current_user
27
+ config_option :user_method
28
+ # This method should return a unique ID for a user. Default: :id
29
+ config_option :user_id_method
30
+ # This method should return the user's name. Default: :name
31
+ config_option :user_name_method
32
+ # This method should return the user's email. Default: :email
33
+ config_option :user_email_method
34
+ # This method should return the user's mobile phone number. Default: :mobile
35
+ config_option :user_mobile_method
36
+
37
+ attr_reader :defaults
38
+
39
+ def initialize
40
+ @config_values = {}
41
+
42
+ # set default attribute values
43
+ @defaults = OpenStruct.new({
44
+ user_method: :current_user,
45
+ user_id_method: :id,
46
+ user_name_method: :name,
47
+ user_email_method: :email,
48
+ user_mobile_method: :mobile
49
+ })
50
+ end
51
+
52
+ def [](key)
53
+ read_value(key)
54
+ end
55
+
56
+ def []=(key, value)
57
+ set_value(key, value)
58
+ end
59
+
60
+ private
61
+
62
+ def read_value(name)
63
+ if @config_values.has_key?(name)
64
+ @config_values[name]
65
+ else
66
+ @defaults.send(name)
67
+ end
68
+ end
69
+
70
+ def set_value(name, value)
71
+ @config_values[name] = value
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,72 @@
1
+ # Include ThisData::TrackRequest in your ApplicationController to get a handy
2
+ # track method which looks at the request and current_user variables to
3
+ # generate an event.
4
+ module ThisData
5
+ module TrackRequest
6
+ class ThisDataTrackError < StandardError; end
7
+
8
+ # Will pull request and user details from the controller, and send an event
9
+ # to ThisData.
10
+ def thisdata_track(verb: ThisData::Verbs::LOG_IN)
11
+ controller = controller_from_env
12
+ user_details = user_details_from_controller(controller)
13
+ event = {
14
+ verb: verb,
15
+ ip: request.remote_ip,
16
+ user_agent: request.user_agent,
17
+ user: user_details
18
+ }
19
+
20
+ ThisData.track(event)
21
+ rescue => e
22
+ ThisData.error "Could not track event:"
23
+ ThisData.error e
24
+ ThisData.error e.backtrace.limit(5).join("\n")
25
+ false
26
+ end
27
+
28
+ private
29
+
30
+ # Rails keeps a reference to the controller in the env variable.
31
+ # Returns a Controller
32
+ def controller_from_env
33
+ unless controller = env["action_controller.instance"]
34
+ raise ThisDataTrackError, "Could not get controller from environment"
35
+ end
36
+ controller
37
+ end
38
+
39
+ # Fetches the user record by calling the configured method on the
40
+ # controller.
41
+ # Will raise a NoMethodError if controller does not respond to the method.
42
+ # Returns an object
43
+ def user_from_controller(controller)
44
+ user = controller.send(ThisData.configuration.user_method)
45
+ end
46
+
47
+ # Will fetch a user and return a Hash of details for that User.
48
+ # Will raise a NoMethodError if controller does not return a user,
49
+ # or we can't get a user id.
50
+ def user_details_from_controller(controller)
51
+ user = user_from_controller(controller)
52
+ {
53
+ id: user.send(ThisData.configuration.user_id_method),
54
+ name: value_if_configured(user, "user_name_method"),
55
+ email: value_if_configured(user, "user_email_method"),
56
+ mobile: value_if_configured(user, "user_mobile_method"),
57
+ }
58
+ end
59
+
60
+ # Will return the result of calling a method defined in ThisData's config
61
+ # if the object responds to that method.
62
+ def value_if_configured(object, config_option)
63
+ method = ThisData.configuration.send("#{config_option}")
64
+ if object.respond_to?(method, true)
65
+ return object.send(method)
66
+ else
67
+ nil
68
+ end
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,10 @@
1
+ module ThisData
2
+ class Verbs
3
+
4
+ LOG_IN = 'log-in'
5
+ LOG_OUT = 'log-out'
6
+ LOG_IN_DENIED = 'log-in-denied'
7
+ LOG_IN_CHALLENGE = 'log-in-challenge'
8
+
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module ThisData
2
+ VERSION = "0.1.0"
3
+ end
data/thisdata.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'this_data/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "thisdata"
8
+ spec.version = ThisData::VERSION
9
+ spec.authors = ["ThisData Ltd", "Nick Malcolm"]
10
+ spec.email = ["support@thisdata.com", "nick@thisdata.com"]
11
+
12
+ spec.summary = %q{Ruby wrapper for ThisData's Login Intelligence API}
13
+ spec.description = %q{Use ThisData's Login Intelligence API in your ruby / rails app to monitor for unusual end-user activity}
14
+ spec.homepage = "https://github.com/thisdata/thisdata-ruby"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+
27
+ spec.executables = []
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_runtime_dependency "httparty", "~> 0.13"
31
+ spec.add_runtime_dependency "json", "~> 1.8"
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.10"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "minitest", "~> 5.8"
36
+ spec.add_development_dependency "fakeweb", "~> 1.3"
37
+ spec.add_development_dependency "mocha", "~> 1.1"
38
+
39
+
40
+ end
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thisdata
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ThisData Ltd
8
+ - Nick Malcolm
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-02-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: httparty
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0.13'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '0.13'
28
+ - !ruby/object:Gem::Dependency
29
+ name: json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.8'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.8'
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.10'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.10'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '10.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '10.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: minitest
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '5.8'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '5.8'
84
+ - !ruby/object:Gem::Dependency
85
+ name: fakeweb
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '1.3'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '1.3'
98
+ - !ruby/object:Gem::Dependency
99
+ name: mocha
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '1.1'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '1.1'
112
+ description: Use ThisData's Login Intelligence API in your ruby / rails app to monitor
113
+ for unusual end-user activity
114
+ email:
115
+ - support@thisdata.com
116
+ - nick@thisdata.com
117
+ executables: []
118
+ extensions: []
119
+ extra_rdoc_files: []
120
+ files:
121
+ - ".gitignore"
122
+ - CHANGELOG
123
+ - Gemfile
124
+ - LICENSE.md
125
+ - README.md
126
+ - Rakefile
127
+ - bin/console
128
+ - bin/setup
129
+ - lib/generators/this_data/install_generator.rb
130
+ - lib/this_data.rb
131
+ - lib/this_data/client.rb
132
+ - lib/this_data/configuration.rb
133
+ - lib/this_data/track_request.rb
134
+ - lib/this_data/verbs.rb
135
+ - lib/this_data/version.rb
136
+ - thisdata.gemspec
137
+ homepage: https://github.com/thisdata/thisdata-ruby
138
+ licenses:
139
+ - MIT
140
+ metadata:
141
+ allowed_push_host: https://rubygems.org
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubyforge_project:
158
+ rubygems_version: 2.4.8
159
+ signing_key:
160
+ specification_version: 4
161
+ summary: Ruby wrapper for ThisData's Login Intelligence API
162
+ test_files: []