tiddle 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bcae34825a51917726a62d76e0c12f219c3bdaff
4
+ data.tar.gz: 7a63e0436d50cdddfa99407d87ef89101491043f
5
+ SHA512:
6
+ metadata.gz: 0506dea0acf421a88fe9b7d225851a095e1095c0d4c69e7e04a0055b92ba2e2945c69f8cf729fe7efdd0c00f3edbad33caebc3c0ef1d2d30977d9bbff3863484
7
+ data.tar.gz: df27a7199bf7690edd4c6a988e86a9358489ae36f24b07b53f8d8a1121db8069f872ea5a7e9d498744a32848ea9993381b4a3c96f81934b26ffaa0b1648651aa
@@ -0,0 +1,18 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .ruby-gemset
16
+ .ruby-version
17
+ *.sqlite3
18
+ *.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tiddle.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Adam Niedzielski
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.
@@ -0,0 +1,76 @@
1
+ # Tiddle
2
+
3
+ Tiddle provides Devise strategy for token authentication in API-only Ruby on Rails applications. Its main feature is **support for multiple tokens per user**.
4
+
5
+ Tiddle is lightweight and non-configurable. It does what it has to do and leaves some manual implementation to you.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'tiddle'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+
20
+ ## Usage
21
+
22
+ 1) Add ```:token_authenticatable``` inside your Devise-enabled model:
23
+
24
+ ```ruby
25
+ class User < ActiveRecord::Base
26
+ devise :database_authenticatable, :registerable,
27
+ :recoverable, :trackable, :validatable,
28
+ :token_authenticatable
29
+ end
30
+ ```
31
+
32
+ 2) Generate the model which stores authentication tokens. The model name is not important, but the Devise-enabled model should have association called ```authentication_tokens```.
33
+
34
+ ```
35
+ rails g model AuthenticationToken body:string user:references last_used_at:datetime ip_address:string user_agent:string
36
+ ```
37
+
38
+ ```ruby
39
+ class User < ActiveRecord::Base
40
+ has_many :authentication_tokens
41
+ end
42
+ ```
43
+
44
+ ```body```, ```last_used_at```, ```ip_address``` and ```user_agent``` fields are required.
45
+
46
+ 3) Customize ```Devise::SessionsController```. You need to create and return token in ```#create``` and expire the token in ```#destroy```.
47
+
48
+ ```ruby
49
+ class Users::SessionsController < Devise::SessionsController
50
+
51
+ def create
52
+ [...]
53
+ token = Tiddle.create_and_return_token(resource)
54
+ render json: { authentication_token: token }
55
+ end
56
+
57
+ def destroy
58
+ Tiddle.expire_token(current_user, request)
59
+ render json: {}
60
+ end
61
+ end
62
+ ```
63
+
64
+ 4) Require authentication for some controller:
65
+
66
+ ```ruby
67
+ class PostsController < ApplicationController
68
+ before_action :authenticate_user!
69
+
70
+ def index
71
+ render json: Post.all
72
+ end
73
+ end
74
+ ```
75
+
76
+ 5) Send ```X-USER-EMAIL``` and ```X-USER-TOKEN``` as headers of every request which requires authentication.
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new(:spec)
4
+
5
+ task :default => :spec
@@ -0,0 +1,4 @@
1
+ en:
2
+ devise:
3
+ failure:
4
+ invalid_token: "Invalid email or token"
@@ -0,0 +1,24 @@
1
+ require "tiddle/version"
2
+ require "tiddle/strategy"
3
+ require "tiddle/rails"
4
+ require "tiddle/token_issuer"
5
+
6
+ module Tiddle
7
+
8
+ def self.create_and_return_token(resource, request)
9
+ TokenIssuer.build.create_and_return_token(resource, request)
10
+ end
11
+
12
+ def self.expire_token(resource, request)
13
+ TokenIssuer.build.expire_token(resource, request)
14
+ end
15
+
16
+ def self.purge_old_tokens(resource)
17
+ TokenIssuer.build.purge_old_tokens(resource)
18
+ end
19
+ end
20
+
21
+ Devise::add_module :token_authenticatable,
22
+ model: 'tiddle/model',
23
+ strategy: true,
24
+ no_input: true
@@ -0,0 +1,6 @@
1
+ module Devise
2
+ module Models
3
+ module TokenAuthenticatable
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ module Tiddle
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,52 @@
1
+ require 'devise/strategies/authenticatable'
2
+
3
+ module Devise
4
+ module Strategies
5
+ class TokenAuthenticatable < Authenticatable
6
+
7
+ def authenticate!
8
+ env["devise.skip_trackable"] = true
9
+
10
+ resource = mapping.to.find_for_authentication(email: email_from_headers)
11
+ return fail(:invalid_token) unless resource
12
+
13
+ resource.authentication_tokens.each do |token|
14
+ if Devise.secure_compare(token.body, token_from_headers)
15
+ touch_token(token)
16
+ return success!(resource)
17
+ end
18
+ end
19
+
20
+ fail(:invalid_token)
21
+ end
22
+
23
+ def valid?
24
+ email_from_headers.present? && token_from_headers.present?
25
+ end
26
+
27
+ def store?
28
+ false
29
+ end
30
+
31
+ private
32
+
33
+ def email_from_headers
34
+ env["HTTP_X_#{model_name}_EMAIL"]
35
+ end
36
+
37
+ def token_from_headers
38
+ env["HTTP_X_#{model_name}_TOKEN"]
39
+ end
40
+
41
+ def model_name
42
+ mapping.to.model_name.to_s.underscore.upcase
43
+ end
44
+
45
+ def touch_token(token)
46
+ token.update_attribute(:last_used_at, DateTime.current) if token.last_used_at < 1.hour.ago
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ Warden::Strategies.add(:token_authenticatable, Devise::Strategies::TokenAuthenticatable)
@@ -0,0 +1,38 @@
1
+ module Tiddle
2
+ class TokenIssuer
3
+ MAXIMUM_TOKENS_PER_USER = 20
4
+
5
+ def self.build
6
+ new(MAXIMUM_TOKENS_PER_USER)
7
+ end
8
+
9
+ def initialize(maximum_tokens_per_user)
10
+ self.maximum_tokens_per_user = maximum_tokens_per_user
11
+ end
12
+
13
+ def create_and_return_token(resource, request)
14
+ token = resource.authentication_tokens.
15
+ create! body: generate_token,
16
+ last_used_at: DateTime.current,
17
+ ip_address: request.remote_ip,
18
+ user_agent: request.user_agent
19
+
20
+ token.body
21
+ end
22
+
23
+ def expire_token(resource, request)
24
+ resource.authentication_tokens.where(body: request.headers["X-#{resource.model_name.to_s.upcase}-TOKEN"]).take!.destroy
25
+ end
26
+
27
+ def purge_old_tokens(resource)
28
+ resource.authentication_tokens.order(last_used_at: :desc).offset(maximum_tokens_per_user).destroy_all
29
+ end
30
+
31
+ private
32
+ attr_accessor :maximum_tokens_per_user
33
+
34
+ def generate_token
35
+ Devise.friendly_token
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,3 @@
1
+ module Tiddle
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,7 @@
1
+ class SecretsController < ApplicationController
2
+ before_action :authenticate_user!
3
+
4
+ def index
5
+ head :ok
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ class AuthenticationToken < ActiveRecord::Base
2
+ end
@@ -0,0 +1,7 @@
1
+ class User < ActiveRecord::Base
2
+ devise :database_authenticatable, :registerable,
3
+ :recoverable, :trackable, :validatable,
4
+ :token_authenticatable
5
+
6
+ has_many :authentication_tokens
7
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ require "active_model/railtie"
4
+ require "active_job/railtie"
5
+ require "active_record/railtie"
6
+ require "action_controller/railtie"
7
+ require "action_mailer/railtie"
8
+ require "action_view/railtie"
9
+
10
+ module RailsApp
11
+ class Application < Rails::Application
12
+ config.eager_load = true
13
+ config.root = File.expand_path('../../.', __FILE__)
14
+ end
15
+ end
16
+
@@ -0,0 +1,2 @@
1
+ ENV['BUNDLE_GEMFILE'] = File.expand_path('../../../../Gemfile', __FILE__)
2
+ require 'bundler/setup'
@@ -0,0 +1,5 @@
1
+ # Load the Rails application.
2
+ require File.expand_path('../application', __FILE__)
3
+
4
+ # Initialize the Rails application.
5
+ Rails.application.initialize!
@@ -0,0 +1,4 @@
1
+ Rails.application.routes.draw do
2
+ devise_for :users
3
+ resources :secrets, only: [:index], defaults: { format: 'json' }
4
+ end
@@ -0,0 +1,2 @@
1
+ test:
2
+ secret_key_base: 01c37cff57639eef8aa511ae6ab64298c1da89dc32dfdda363473716f49e25d2473e48b6253c69d17c8ae8c9b6a027ec5a4ac0ffbd6c06defe1b70dd2ef32df8
@@ -0,0 +1,35 @@
1
+ class CreateTables < ActiveRecord::Migration
2
+ def change
3
+ create_table(:users) do |t|
4
+ ## Database authenticatable
5
+ t.string :email, null: false, default: ""
6
+ t.string :encrypted_password, null: false, default: ""
7
+
8
+ ## Recoverable
9
+ t.string :reset_password_token
10
+ t.datetime :reset_password_sent_at
11
+
12
+ ## Trackable
13
+ t.integer :sign_in_count, default: 0, null: false
14
+ t.datetime :current_sign_in_at
15
+ t.datetime :last_sign_in_at
16
+ t.string :current_sign_in_ip
17
+ t.string :last_sign_in_ip
18
+
19
+ t.timestamps null: false
20
+ end
21
+
22
+ add_index :users, :email, unique: true
23
+ add_index :users, :reset_password_token, unique: true
24
+ end
25
+
26
+ create_table :authentication_tokens do |t|
27
+ t.string :body, null: false
28
+ t.references :user, index: true, null: false
29
+ t.datetime :last_used_at, null: false
30
+ t.string :ip_address
31
+ t.string :user_agent
32
+
33
+ t.timestamps null: false
34
+ end
35
+ end
@@ -0,0 +1,111 @@
1
+ ENV["RAILS_ENV"] = 'test'
2
+ ENV["DATABASE_URL"] = "sqlite3:db/test.sqlite3"
3
+
4
+ require 'rails/all'
5
+ require 'rspec/rails'
6
+ require 'devise'
7
+ require 'devise/orm/active_record'
8
+ require 'tiddle'
9
+
10
+ require 'rails_app/config/environment'
11
+
12
+ Dir[__dir__ + "/support/**/*.rb"].each { |f| require f }
13
+
14
+ # This file was generated by the `rspec --init` command. Conventionally, all
15
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
16
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
17
+ # this file to always be loaded, without a need to explicitly require it in any
18
+ # files.
19
+ #
20
+ # Given that it is always loaded, you are encouraged to keep this file as
21
+ # light-weight as possible. Requiring heavyweight dependencies from this file
22
+ # will add to the boot time of your test suite on EVERY test run, even for an
23
+ # individual file that may not need all of that loaded. Instead, consider making
24
+ # a separate helper file that requires the additional dependencies and performs
25
+ # the additional setup, and require it from the spec files that actually need
26
+ # it.
27
+ #
28
+ # The `.rspec` file also contains a few flags that are not defaults but that
29
+ # users commonly want.
30
+ #
31
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
32
+ RSpec.configure do |config|
33
+ # rspec-expectations config goes here. You can use an alternate
34
+ # assertion/expectation library such as wrong or the stdlib/minitest
35
+ # assertions if you prefer.
36
+ config.expect_with :rspec do |expectations|
37
+ # This option will default to `true` in RSpec 4. It makes the `description`
38
+ # and `failure_message` of custom matchers include text for helper methods
39
+ # defined using `chain`, e.g.:
40
+ # be_bigger_than(2).and_smaller_than(4).description
41
+ # # => "be bigger than 2 and smaller than 4"
42
+ # ...rather than:
43
+ # # => "be bigger than 2"
44
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
45
+ end
46
+
47
+ # rspec-mocks config goes here. You can use an alternate test double
48
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
49
+ config.mock_with :rspec do |mocks|
50
+ # Prevents you from mocking or stubbing a method that does not exist on
51
+ # a real object. This is generally recommended, and will default to
52
+ # `true` in RSpec 4.
53
+ mocks.verify_partial_doubles = true
54
+ end
55
+
56
+ config.before(:suite) do
57
+ # Do initial migration
58
+ ActiveRecord::Migrator.migrate(File.expand_path("rails_app/db/migrate/", File.dirname(__FILE__)))
59
+ end
60
+
61
+ config.use_transactional_fixtures = true
62
+
63
+ # The settings below are suggested to provide a good initial experience
64
+ # with RSpec, but feel free to customize to your heart's content.
65
+ =begin
66
+ # These two settings work together to allow you to limit a spec run
67
+ # to individual examples or groups you care about by tagging them with
68
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
69
+ # get run.
70
+ config.filter_run :focus
71
+ config.run_all_when_everything_filtered = true
72
+
73
+ # Limits the available syntax to the non-monkey patched syntax that is
74
+ # recommended. For more details, see:
75
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
76
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
77
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
78
+ config.disable_monkey_patching!
79
+
80
+ # This setting enables warnings. It's recommended, but in some cases may
81
+ # be too noisy due to issues in dependencies.
82
+ config.warnings = true
83
+
84
+ # Many RSpec users commonly either run the entire suite or an individual
85
+ # file, and it's useful to allow more verbose output when running an
86
+ # individual spec file.
87
+ if config.files_to_run.one?
88
+ # Use the documentation formatter for detailed output,
89
+ # unless a formatter has already been configured
90
+ # (e.g. via a command-line flag).
91
+ config.default_formatter = 'doc'
92
+ end
93
+
94
+ # Print the 10 slowest examples and example groups at the
95
+ # end of the spec run, to help surface which specs are running
96
+ # particularly slow.
97
+ config.profile_examples = 10
98
+
99
+ # Run specs in random order to surface order dependencies. If you find an
100
+ # order dependency and want to debug it, you can fix the order by providing
101
+ # the seed, which is printed after each run.
102
+ # --seed 1234
103
+ config.order = :random
104
+
105
+ # Seed global randomization in this process using the `--seed` CLI option.
106
+ # Setting this allows you to use `--seed` to deterministically reproduce
107
+ # test failures related to randomization by passing the same `--seed` value
108
+ # as the one that triggered the failure.
109
+ Kernel.srand config.seed
110
+ =end
111
+ end
@@ -0,0 +1,68 @@
1
+ describe "Authentication using Tiddle strategy", type: :request do
2
+
3
+ before do
4
+ @user = User.create!(email: "test@example.com", password: "12345678")
5
+ @token = Tiddle.create_and_return_token(@user, FakeRequest.new)
6
+ end
7
+
8
+ context "with valid email and token" do
9
+
10
+ it "allows to access endpoints which require authentication" do
11
+ get secrets_path, {}, { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token }
12
+ expect(response.status).to eq 200
13
+ end
14
+
15
+ describe "touching token" do
16
+
17
+ context "when token was last used more than hour ago" do
18
+
19
+ before do
20
+ @user.authentication_tokens.last.update_attribute(:last_used_at, 2.hours.ago)
21
+ end
22
+
23
+ it "updates last_used_at field" do
24
+ expect do
25
+ get secrets_path, {}, { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token }
26
+ end.to change { @user.authentication_tokens.last.last_used_at }
27
+ end
28
+ end
29
+
30
+ context "when token was last used less than hour ago" do
31
+
32
+ before do
33
+ @user.authentication_tokens.last.update_attribute(:last_used_at, 30.minutes.ago)
34
+ end
35
+
36
+ it "does not update last_used_at field" do
37
+ expect do
38
+ get secrets_path, {}, { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token }
39
+ end.not_to change { @user.authentication_tokens.last.last_used_at }
40
+ end
41
+ end
42
+ end
43
+
44
+ context "when email contains uppercase letters" do
45
+
46
+ it "converts email to lower case and authenticates user" do
47
+ get secrets_path, {}, { "X-USER-EMAIL" => "TEST@example.com", "X-USER-TOKEN" => @token }
48
+ expect(response.status).to eq 200
49
+ end
50
+ end
51
+ end
52
+
53
+ context "with invalid email and valid token" do
54
+
55
+ it "does not allow to access endpoints which require authentication" do
56
+ get secrets_path, {}, { "X-USER-EMAIL" => "wrong@example.com", "X-USER-TOKEN" => @token }
57
+ expect(response.status).to eq 401
58
+ end
59
+ end
60
+
61
+ context "with valid email and invalid token" do
62
+
63
+ it "does not allow to access endpoints which require authentication" do
64
+ get secrets_path, {}, { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => "wrong" }
65
+ expect(response.status).to eq 401
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,16 @@
1
+ class FakeRequest
2
+
3
+ def initialize(
4
+ remote_ip: "23.12.54.111",
5
+ user_agent: "I am not a bot",
6
+ headers: {}
7
+ )
8
+ self.remote_ip = remote_ip
9
+ self.user_agent = user_agent
10
+ self.headers = headers
11
+ end
12
+
13
+ attr_accessor :remote_ip
14
+ attr_accessor :user_agent
15
+ attr_accessor :headers
16
+ end
@@ -0,0 +1,70 @@
1
+ describe Tiddle do
2
+
3
+ before do
4
+ @user = User.create!(email: "test@example.com", password: "12345678")
5
+ end
6
+
7
+ describe "create_and_return_token" do
8
+
9
+ it "returns string with token" do
10
+ result = Tiddle.create_and_return_token(@user, FakeRequest.new)
11
+ expect(result).to be_present
12
+ end
13
+
14
+ it "creates new token in the database" do
15
+ expect do
16
+ Tiddle.create_and_return_token(@user, FakeRequest.new)
17
+ end.to change { @user.authentication_tokens.count }.by(1)
18
+ end
19
+
20
+ it "sets last_used_at field" do
21
+ Tiddle.create_and_return_token(@user, FakeRequest.new)
22
+ expect(@user.authentication_tokens.last.last_used_at).to be_within(1).of(DateTime.current)
23
+ end
24
+
25
+ it "saves ip address" do
26
+ Tiddle.create_and_return_token(@user, FakeRequest.new(remote_ip: "123.101.54.1"))
27
+ expect(@user.authentication_tokens.last.ip_address).to eq "123.101.54.1"
28
+ end
29
+
30
+ it "saves user agent" do
31
+ Tiddle.create_and_return_token(@user, FakeRequest.new(user_agent: "Internet Explorer 4.0"))
32
+ expect(@user.authentication_tokens.last.user_agent).to eq "Internet Explorer 4.0"
33
+ end
34
+ end
35
+
36
+ describe "expire_token" do
37
+
38
+ before do
39
+ token = Tiddle.create_and_return_token(@user, FakeRequest.new)
40
+ @request = FakeRequest.new(headers: { "X-USER-TOKEN" => token })
41
+ end
42
+
43
+ it "deletes token from the database" do
44
+ expect do
45
+ Tiddle.expire_token(@user, @request)
46
+ end.to change { @user.authentication_tokens.count }.by(-1)
47
+ end
48
+ end
49
+
50
+ describe "purge_old_tokens" do
51
+
52
+ before do
53
+ Tiddle.create_and_return_token(@user, FakeRequest.new)
54
+ @old = @user.authentication_tokens.last
55
+ @old.update_attribute(:last_used_at, 2.hours.ago)
56
+
57
+ Tiddle.create_and_return_token(@user, FakeRequest.new)
58
+ @new = @user.authentication_tokens.last
59
+ @new.update_attribute(:last_used_at, 10.minutes.ago)
60
+ end
61
+
62
+ it "deletes old tokens which are over the limit" do
63
+ expect do
64
+ Tiddle::TokenIssuer.new(1).purge_old_tokens(@user)
65
+ end.to change { @user.authentication_tokens.count }.from(2).to(1)
66
+
67
+ expect(@user.authentication_tokens.last).to eq @new
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'tiddle/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "tiddle"
8
+ spec.version = Tiddle::VERSION
9
+ spec.authors = ["Adam Niedzielski"]
10
+ spec.email = ["adamsunday@gmail.com"]
11
+ spec.summary = %q{Token authentication for Devise which supports multiple tokens per model}
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.required_ruby_version = '~> 2.2.0'
21
+
22
+ spec.add_dependency "devise", "~> 3.4.1"
23
+ spec.add_dependency "activerecord", "~> 4.2.0"
24
+ spec.add_development_dependency "bundler", "~> 1.7"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec-rails"
27
+ spec.add_development_dependency "rails", "~> 4.2.0"
28
+ spec.add_development_dependency "sqlite3"
29
+ end
metadata ADDED
@@ -0,0 +1,184 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tiddle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Niedzielski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: devise
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.4.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.4.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 4.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 4.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 4.2.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 4.2.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description:
112
+ email:
113
+ - adamsunday@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rspec"
120
+ - Gemfile
121
+ - LICENSE.txt
122
+ - README.md
123
+ - Rakefile
124
+ - config/locales/en.yml
125
+ - lib/tiddle.rb
126
+ - lib/tiddle/model.rb
127
+ - lib/tiddle/rails.rb
128
+ - lib/tiddle/strategy.rb
129
+ - lib/tiddle/token_issuer.rb
130
+ - lib/tiddle/version.rb
131
+ - spec/rails_app/app/controllers/application_controller.rb
132
+ - spec/rails_app/app/controllers/secrets_controller.rb
133
+ - spec/rails_app/app/models/authentication_token.rb
134
+ - spec/rails_app/app/models/user.rb
135
+ - spec/rails_app/config/application.rb
136
+ - spec/rails_app/config/boot.rb
137
+ - spec/rails_app/config/environment.rb
138
+ - spec/rails_app/config/routes.rb
139
+ - spec/rails_app/config/secrets.yml
140
+ - spec/rails_app/db/migrate/20150217000000_create_tables.rb
141
+ - spec/spec_helper.rb
142
+ - spec/strategy_spec.rb
143
+ - spec/support/fake_request.rb
144
+ - spec/tiddle_spec.rb
145
+ - tiddle.gemspec
146
+ homepage: ''
147
+ licenses:
148
+ - MIT
149
+ metadata: {}
150
+ post_install_message:
151
+ rdoc_options: []
152
+ require_paths:
153
+ - lib
154
+ required_ruby_version: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: 2.2.0
159
+ required_rubygems_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ requirements: []
165
+ rubyforge_project:
166
+ rubygems_version: 2.4.5
167
+ signing_key:
168
+ specification_version: 4
169
+ summary: Token authentication for Devise which supports multiple tokens per model
170
+ test_files:
171
+ - spec/rails_app/app/controllers/application_controller.rb
172
+ - spec/rails_app/app/controllers/secrets_controller.rb
173
+ - spec/rails_app/app/models/authentication_token.rb
174
+ - spec/rails_app/app/models/user.rb
175
+ - spec/rails_app/config/application.rb
176
+ - spec/rails_app/config/boot.rb
177
+ - spec/rails_app/config/environment.rb
178
+ - spec/rails_app/config/routes.rb
179
+ - spec/rails_app/config/secrets.yml
180
+ - spec/rails_app/db/migrate/20150217000000_create_tables.rb
181
+ - spec/spec_helper.rb
182
+ - spec/strategy_spec.rb
183
+ - spec/support/fake_request.rb
184
+ - spec/tiddle_spec.rb