castle-keep 0.1.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/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/README.md +58 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/castle-keep.gemspec +26 -0
- data/lib/castle/keep.rb +104 -0
- data/lib/castle/keep/version.rb +3 -0
- metadata +98 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ec4cf3c15dd8218d822f0a8635de41fe99006bae
|
4
|
+
data.tar.gz: 068c655b6981ab13c5cba2d7c620cbecf899fdb7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a3ec81aa9817fe03b21db498ebe99f52c2121eeceb46279ae8b31bd7fc67089fd8e59e492a5d896268258cca5a5297bb3be9713a91e2c9381f7404b0a2e2d44f
|
7
|
+
data.tar.gz: 99457f15fe16662ba502dea27029da44645b11155dddc25e58551a5562f6609c42363332dc3eddb03a7f617d89ec36a228177a6eabc33ffd0eda25f8bcbbb286
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# Castle::Keep
|
2
|
+
|
3
|
+
This is a minimal implementation of the Castle.io Server-Side API.
|
4
|
+
This gem exists because the official [castle-rb](https://github.com/castle/castle-ruby) gem has quite a few external dependencies that can cause compatibility issues.
|
5
|
+
|
6
|
+
The code for the initial version of this gem was taken directly from [carlhoerberg](https://github.com/carlhoerberg)'s [gist](https://gist.github.com/carlhoerberg/d5537dd3990c7e3042942f587801b9cd)
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'castle-keep'
|
14
|
+
```
|
15
|
+
|
16
|
+
Load and configure the library with your Castle API secret in an initializer or similar.
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
Castle.api_secret = 'YOUR_API_SECRET'
|
20
|
+
```
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
A new instance of `Castle::Keep` should be created for each request that comes through your stack.
|
25
|
+
I recommend using a per-request global storage system like [request_store](https://github.com/steveklabnik/request_store)
|
26
|
+
|
27
|
+
Rails Example:
|
28
|
+
```ruby
|
29
|
+
class ApplicationController < ActionController::Base
|
30
|
+
before_filter :_set_castle
|
31
|
+
|
32
|
+
private
|
33
|
+
def _set_castle
|
34
|
+
RequestStore.store[:castle] = Castle::Keep.create_context(request)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
Once the helper is loaded you can then do:
|
40
|
+
```ruby
|
41
|
+
begin
|
42
|
+
RequestStore.store[:castle].track(
|
43
|
+
name: '$login.succeeded',
|
44
|
+
user_id: user.id)
|
45
|
+
rescue Castle::Error => e
|
46
|
+
puts e.message
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
## Development
|
51
|
+
|
52
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
53
|
+
|
54
|
+
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).
|
55
|
+
|
56
|
+
## Contributing
|
57
|
+
|
58
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/thekidcoder/castle-keep.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "castle/keep"
|
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
data/castle-keep.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'castle/keep/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "castle-keep"
|
8
|
+
spec.version = Castle::VERSION
|
9
|
+
spec.authors = ["Christopher Ostrowski"]
|
10
|
+
spec.email = ["chris.ostrowski@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Simplified version of the castle-rb gem. Minimized dependencies for maximum compatibility.}
|
13
|
+
spec.description = %q{Simplified version of the castle-rb gem. Minimized dependencies for maximum compatibility.}
|
14
|
+
spec.homepage = "https://github.com/TheKidCoder/Castle-Keep"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
26
|
+
end
|
data/lib/castle/keep.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'castle/keep/version'
|
2
|
+
require 'net/https'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Castle
|
6
|
+
def self.api_key
|
7
|
+
@@api_key
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.api_key=(api_key)
|
11
|
+
@@api_key = api_key
|
12
|
+
end
|
13
|
+
|
14
|
+
class Keep
|
15
|
+
def self.create_context(request)
|
16
|
+
Castle::Keep.new(request.cookies['__cid'], request.ip, request.env.keys.grep(/^HTTP_/).map do |header|
|
17
|
+
name = header.gsub(/^HTTP_/, '').split('_').map(&:capitalize).join('-')
|
18
|
+
unless name == "Cookie"
|
19
|
+
{ name => request.env[header] }
|
20
|
+
end
|
21
|
+
end.compact.inject(:merge))
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(cookie_id, ip, headers)
|
25
|
+
@http = Net::HTTP.new "api.castle.io", 443
|
26
|
+
@http.use_ssl = true
|
27
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
28
|
+
@headers = {
|
29
|
+
"Content-Type" => "application/json",
|
30
|
+
"X-Castle-Cookie-Id" => cookie_id,
|
31
|
+
"X-Castle-Ip" => ip,
|
32
|
+
"X-Castle-Headers" => headers.to_json,
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
# Available events:
|
37
|
+
# $login.succeeded: Record when a user attempts to log in.
|
38
|
+
# $login.failed: Record when a user login failed.
|
39
|
+
# $logout.succeeded: Record when a user logs out.
|
40
|
+
# $registration.succeeded: Capture account creation, both when a user signs up as well as when created manually by an administrator.
|
41
|
+
# $registration.failed: Record when an account failed to be created.
|
42
|
+
# $email_change.requested: An attempt was made to change a user’s email.
|
43
|
+
# $email_change.succeeded: The user completed all of the steps in the email address change process and the email was successfully changed.
|
44
|
+
# $email_change.failed: Use to record when a user failed to change their email address.
|
45
|
+
# $password_reset.requested: An attempt was made to reset a user’s password.
|
46
|
+
# $password_reset.succeeded: The user completed all of the steps in the password reset process and the password was successfully reset. Password resets do not required knowledge of the current password.
|
47
|
+
# $password_reset.failed: Use to record when a user failed to reset their password.
|
48
|
+
# $password_change.succeeded: Use to record when a user changed their password. This event is only logged when users change their own password.
|
49
|
+
# $password_change.failed: Use to record when a user failed to change their password.
|
50
|
+
def track(event_name, user_id: nil, details: nil)
|
51
|
+
if user_id.nil? && details.nil?
|
52
|
+
fail ArgumentError, "Missing both user_id and details"
|
53
|
+
end
|
54
|
+
|
55
|
+
req = Net::HTTP::Post.new("/v1/events", @headers)
|
56
|
+
req.basic_auth("", Castle.api_key)
|
57
|
+
req.body = { name: event_name, user_id: user_id, details: details }.to_json
|
58
|
+
response = @http.request(req)
|
59
|
+
unless response.code.to_i == 204
|
60
|
+
fail Error, "Response code: #{response.code}\nResponse body: #{response.body}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def events(user_id, page: 1, page_size: 200)
|
65
|
+
req = Net::HTTP::Get.new("/v1/events?query=user_id:#{user_id}&page=#{page}&page_size=#{page_size}", @headers)
|
66
|
+
req.basic_auth("", Castle.api_key)
|
67
|
+
response = @http.request(req)
|
68
|
+
unless response.code.to_i == 200
|
69
|
+
fail Error, "Response code: #{response.code}\nResponse body: #{response.body}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def create_auth(user_id)
|
74
|
+
req = Net::HTTP::Post.new("/v1/authentications", @headers)
|
75
|
+
req.basic_auth("", Castle.api_key)
|
76
|
+
req.body = { user_id: user_id }.to_json
|
77
|
+
response = @http.request(req)
|
78
|
+
unless response.code.to_i == 201
|
79
|
+
fail Error, "Response code: #{response.code}\nResponse body: #{response.body}"
|
80
|
+
end
|
81
|
+
JSON.parse response.body
|
82
|
+
end
|
83
|
+
|
84
|
+
def approve_auth(auth_id)
|
85
|
+
req = Net::HTTP::Post.new("/v1/authentications/#{auth_id}/approve", @headers)
|
86
|
+
req.basic_auth("", Castle.api_key)
|
87
|
+
response = @http.request(req)
|
88
|
+
unless response.code.to_i == 204
|
89
|
+
fail Error, "Response code: #{response.code}\nResponse body: #{response.body}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def deny_auth(auth_id)
|
94
|
+
req = Net::HTTP::Post.new("/v1/authentications/#{auth_id}/deny", @headers)
|
95
|
+
req.basic_auth("", Castle.api_key)
|
96
|
+
response = @http.request(req)
|
97
|
+
unless response.code.to_i == 204
|
98
|
+
fail Error, "Response code: #{response.code}\nResponse body: #{response.body}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Error < StandardError; end
|
103
|
+
end
|
104
|
+
end
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: castle-keep
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christopher Ostrowski
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: Simplified version of the castle-rb gem. Minimized dependencies for maximum
|
56
|
+
compatibility.
|
57
|
+
email:
|
58
|
+
- chris.ostrowski@gmail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".rspec"
|
65
|
+
- ".travis.yml"
|
66
|
+
- Gemfile
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- bin/console
|
70
|
+
- bin/setup
|
71
|
+
- castle-keep.gemspec
|
72
|
+
- lib/castle/keep.rb
|
73
|
+
- lib/castle/keep/version.rb
|
74
|
+
homepage: https://github.com/TheKidCoder/Castle-Keep
|
75
|
+
licenses: []
|
76
|
+
metadata: {}
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project:
|
93
|
+
rubygems_version: 2.5.1
|
94
|
+
signing_key:
|
95
|
+
specification_version: 4
|
96
|
+
summary: Simplified version of the castle-rb gem. Minimized dependencies for maximum
|
97
|
+
compatibility.
|
98
|
+
test_files: []
|