periscope_rails 0.0.4 → 0.0.5
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.
- data/Gemfile.lock +92 -94
- data/app/periscope/periscope_controller.rb +83 -76
- data/config/routes.rb +3 -3
- data/lib/periscope_rails/config.rb +58 -51
- data/lib/periscope_rails/engine.rb +3 -3
- data/lib/periscope_rails/version.rb +3 -3
- data/periscope_rails.gemspec +22 -22
- metadata +7 -17
data/Gemfile.lock
CHANGED
@@ -1,94 +1,92 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
periscope_rails (0.0.
|
5
|
-
activesupport (~> 3.
|
6
|
-
rails (~> 3.
|
7
|
-
|
8
|
-
GEM
|
9
|
-
remote: http://rubygems.org/
|
10
|
-
specs:
|
11
|
-
actionmailer (3.
|
12
|
-
actionpack (= 3.
|
13
|
-
mail (~> 2.
|
14
|
-
actionpack (3.
|
15
|
-
activemodel (= 3.
|
16
|
-
activesupport (= 3.
|
17
|
-
builder (~> 3.0.0)
|
18
|
-
erubis (~> 2.7.0)
|
19
|
-
|
20
|
-
rack (~> 1.
|
21
|
-
rack-cache (~> 1.
|
22
|
-
rack-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
json (1.6.
|
45
|
-
mail (2.
|
46
|
-
i18n (>= 0.4.0)
|
47
|
-
mime-types (~> 1.16)
|
48
|
-
treetop (~> 1.4.8)
|
49
|
-
mime-types (1.
|
50
|
-
multi_json (1.
|
51
|
-
polyglot (0.3.3)
|
52
|
-
rack (1.
|
53
|
-
rack-cache (1.
|
54
|
-
rack (>= 0.4)
|
55
|
-
rack-
|
56
|
-
rack
|
57
|
-
rack-
|
58
|
-
rack
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
DEPENDENCIES
|
94
|
-
periscope_rails!
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
periscope_rails (0.0.5)
|
5
|
+
activesupport (~> 3.0)
|
6
|
+
rails (~> 3.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actionmailer (3.2.3)
|
12
|
+
actionpack (= 3.2.3)
|
13
|
+
mail (~> 2.4.4)
|
14
|
+
actionpack (3.2.3)
|
15
|
+
activemodel (= 3.2.3)
|
16
|
+
activesupport (= 3.2.3)
|
17
|
+
builder (~> 3.0.0)
|
18
|
+
erubis (~> 2.7.0)
|
19
|
+
journey (~> 1.0.1)
|
20
|
+
rack (~> 1.4.0)
|
21
|
+
rack-cache (~> 1.2)
|
22
|
+
rack-test (~> 0.6.1)
|
23
|
+
sprockets (~> 2.1.2)
|
24
|
+
activemodel (3.2.3)
|
25
|
+
activesupport (= 3.2.3)
|
26
|
+
builder (~> 3.0.0)
|
27
|
+
activerecord (3.2.3)
|
28
|
+
activemodel (= 3.2.3)
|
29
|
+
activesupport (= 3.2.3)
|
30
|
+
arel (~> 3.0.2)
|
31
|
+
tzinfo (~> 0.3.29)
|
32
|
+
activeresource (3.2.3)
|
33
|
+
activemodel (= 3.2.3)
|
34
|
+
activesupport (= 3.2.3)
|
35
|
+
activesupport (3.2.3)
|
36
|
+
i18n (~> 0.6)
|
37
|
+
multi_json (~> 1.0)
|
38
|
+
arel (3.0.2)
|
39
|
+
builder (3.0.0)
|
40
|
+
erubis (2.7.0)
|
41
|
+
hike (1.2.1)
|
42
|
+
i18n (0.6.0)
|
43
|
+
journey (1.0.3)
|
44
|
+
json (1.6.6)
|
45
|
+
mail (2.4.4)
|
46
|
+
i18n (>= 0.4.0)
|
47
|
+
mime-types (~> 1.16)
|
48
|
+
treetop (~> 1.4.8)
|
49
|
+
mime-types (1.18)
|
50
|
+
multi_json (1.3.2)
|
51
|
+
polyglot (0.3.3)
|
52
|
+
rack (1.4.1)
|
53
|
+
rack-cache (1.2)
|
54
|
+
rack (>= 0.4)
|
55
|
+
rack-ssl (1.3.2)
|
56
|
+
rack
|
57
|
+
rack-test (0.6.1)
|
58
|
+
rack (>= 1.0)
|
59
|
+
rails (3.2.3)
|
60
|
+
actionmailer (= 3.2.3)
|
61
|
+
actionpack (= 3.2.3)
|
62
|
+
activerecord (= 3.2.3)
|
63
|
+
activeresource (= 3.2.3)
|
64
|
+
activesupport (= 3.2.3)
|
65
|
+
bundler (~> 1.0)
|
66
|
+
railties (= 3.2.3)
|
67
|
+
railties (3.2.3)
|
68
|
+
actionpack (= 3.2.3)
|
69
|
+
activesupport (= 3.2.3)
|
70
|
+
rack-ssl (~> 1.3.2)
|
71
|
+
rake (>= 0.8.7)
|
72
|
+
rdoc (~> 3.4)
|
73
|
+
thor (~> 0.14.6)
|
74
|
+
rake (0.9.2.2)
|
75
|
+
rdoc (3.12)
|
76
|
+
json (~> 1.4)
|
77
|
+
sprockets (2.1.2)
|
78
|
+
hike (~> 1.2)
|
79
|
+
rack (~> 1.0)
|
80
|
+
tilt (~> 1.1, != 1.3.0)
|
81
|
+
thor (0.14.6)
|
82
|
+
tilt (1.3.3)
|
83
|
+
treetop (1.4.10)
|
84
|
+
polyglot
|
85
|
+
polyglot (>= 0.3.1)
|
86
|
+
tzinfo (0.3.33)
|
87
|
+
|
88
|
+
PLATFORMS
|
89
|
+
x86-mingw32
|
90
|
+
|
91
|
+
DEPENDENCIES
|
92
|
+
periscope_rails!
|
@@ -1,76 +1,83 @@
|
|
1
|
-
class PeriscopeController <
|
2
|
-
before_filter :authenticate
|
3
|
-
protect_from_forgery :except => [:look, :login]
|
4
|
-
|
5
|
-
def look
|
6
|
-
if !params[:sql].nil?
|
7
|
-
render :json => run_sql(params[:sql])
|
8
|
-
else
|
9
|
-
render :json => {:error => "Command not understood"}
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def login
|
14
|
-
render :json => get_info()
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def authenticate
|
20
|
-
unless PeriscopeRails::Config.check_password(params[:password].to_s)
|
21
|
-
render :json => {:error => "Password invalid."}
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def run_sql(sql_command)
|
26
|
-
#TODO: protect based on CFG, not blacklist
|
27
|
-
bad_words = %W{drop delete update into insert index add remove grant revoke create createdb}
|
28
|
-
bad_words += %W{createuser createrole destroy disconnect exec execute dropdb primary key rollback ; --}
|
29
|
-
|
30
|
-
rows = nil
|
31
|
-
error_message = nil
|
32
|
-
command = sql_command.to_s.strip
|
33
|
-
command_words = command.downcase.gsub(/[^a-zA-Z0-9]/, " ").gsub(/\s+/, " ").split(" ")
|
34
|
-
if command == ""
|
35
|
-
#nothing
|
36
|
-
elsif (command_words & bad_words).size > 0
|
37
|
-
error_message = "Potentially harmful keyword found, blocking script."
|
38
|
-
else
|
39
|
-
begin
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
1
|
+
class PeriscopeController < ActionController::Base
|
2
|
+
before_filter :authenticate
|
3
|
+
protect_from_forgery :except => [:look, :login]
|
4
|
+
|
5
|
+
def look
|
6
|
+
if !params[:sql].nil?
|
7
|
+
render :json => run_sql(params[:sql])
|
8
|
+
else
|
9
|
+
render :json => {:error => "Command not understood"}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def login
|
14
|
+
render :json => get_info()
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def authenticate
|
20
|
+
unless PeriscopeRails::Config.check_password(params[:password].to_s)
|
21
|
+
render :json => {:error => "Password invalid."}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def run_sql(sql_command)
|
26
|
+
#TODO: protect based on CFG, not blacklist
|
27
|
+
bad_words = %W{drop delete update into insert index add remove grant revoke create createdb}
|
28
|
+
bad_words += %W{createuser createrole destroy disconnect exec execute dropdb primary key rollback ; --}
|
29
|
+
|
30
|
+
rows = nil
|
31
|
+
error_message = nil
|
32
|
+
command = sql_command.to_s.strip
|
33
|
+
command_words = command.downcase.gsub(/[^a-zA-Z0-9]/, " ").gsub(/\s+/, " ").split(" ")
|
34
|
+
if command == ""
|
35
|
+
#nothing
|
36
|
+
elsif (command_words & bad_words).size > 0
|
37
|
+
error_message = "Potentially harmful keyword found, blocking script."
|
38
|
+
else
|
39
|
+
begin
|
40
|
+
active_record = PeriscopeRails::Config.get_active_record()
|
41
|
+
active_record.transaction do
|
42
|
+
if PeriscopeRails::Config.block_expensive_queries?
|
43
|
+
cost_row = ""
|
44
|
+
begin
|
45
|
+
cost_row = active_record.connection.select_all("explain #{command}")[0]["QUERY PLAN"]
|
46
|
+
rescue
|
47
|
+
puts "Warning: Periscope was unable to cost this query (1): #{command}"
|
48
|
+
end
|
49
|
+
cost_row =~ /rows=(\d+) width=(\d+)\)$/
|
50
|
+
row_count, width = $1.to_i, $2.to_i
|
51
|
+
if row_count > 0 and width > 0
|
52
|
+
raise "Command blocked, it may be too slow. Estimated at #{row_count} rows, commands must return fewer than #{PeriscopeRails::Config.max_rows} rows." if row_count > PeriscopeRails::Config.max_rows
|
53
|
+
raise "Command blocked, it may be too slow. Estimated at #{row_count * width} bytes, commands use less than #{PeriscopeRails::Config.max_size} bytes." if row_count * width > PeriscopeRails::Config.max_size
|
54
|
+
else
|
55
|
+
puts "Warning: Periscope was unable to cost this query (2): #{command}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
rows = active_record.connection.select_all(command)
|
59
|
+
rows.each do |row|
|
60
|
+
row.each_key do |column|
|
61
|
+
if PeriscopeRails::Config.matches_filter(column)
|
62
|
+
row[column] = '[FILTERED]'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
raise "OK" #abort all transactions for extra protection
|
67
|
+
end
|
68
|
+
rescue Exception => e
|
69
|
+
error_message = e.message unless e.message == "OK"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
return {:error => error_message, :data => rows}
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_info
|
76
|
+
tables = []
|
77
|
+
table_names = ActiveRecord::Base.connection.tables.sort
|
78
|
+
table_names.each do |table_name|
|
79
|
+
tables << {:name => table_name, :columns => ActiveRecord::Base.connection.columns(table_name)}
|
80
|
+
end
|
81
|
+
return {:tables => tables, :error => nil}
|
82
|
+
end
|
83
|
+
end
|
data/config/routes.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Rails.application.routes.draw do
|
2
|
-
post "periscope/login" => "periscope#login"
|
3
|
-
post "periscope/look" => "periscope#look"
|
1
|
+
Rails.application.routes.draw do
|
2
|
+
post "periscope/login" => "periscope#login"
|
3
|
+
post "periscope/look" => "periscope#look"
|
4
4
|
end
|
@@ -1,51 +1,58 @@
|
|
1
|
-
module PeriscopeRails
|
2
|
-
class Config
|
3
|
-
VALID_MATCHTYPES = ['fuzzy', 'exact']
|
4
|
-
|
5
|
-
@@password = nil
|
6
|
-
@@filter = nil
|
7
|
-
@@filter_matchtype = 'fuzzy'
|
8
|
-
@@active_record = nil
|
9
|
-
@@db_username = nil
|
10
|
-
@@db_password = nil
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def self.
|
17
|
-
@@
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
@@
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
return
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
@@
|
47
|
-
return @@active_record
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
1
|
+
module PeriscopeRails
|
2
|
+
class Config
|
3
|
+
VALID_MATCHTYPES = ['fuzzy', 'exact']
|
4
|
+
|
5
|
+
@@password = nil
|
6
|
+
@@filter = nil
|
7
|
+
@@filter_matchtype = 'fuzzy'
|
8
|
+
@@active_record = nil
|
9
|
+
@@db_username = nil
|
10
|
+
@@db_password = nil
|
11
|
+
|
12
|
+
@@block_expensive_queries = true
|
13
|
+
@@max_rows = 1000
|
14
|
+
@@max_size = @@max_rows * 500
|
15
|
+
|
16
|
+
def self.set_password(password)
|
17
|
+
@@password = password
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.set_filter(options)
|
21
|
+
@@filter = options[:filter] if options[:filter] and options[:filter].class == Array
|
22
|
+
@@filter_matchtype = options[:matchtype] if options.has_key?(:matchtype) and VALID_MATCHTYPES.include?(options[:matchtype])
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.use_db_credentials(options)
|
26
|
+
@@db_username = options[:username] if options[:username] and options[:username].class == String
|
27
|
+
@@db_password = options[:password] if options[:password] and options[:password].class == String
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.check_password(password)
|
31
|
+
return @@password == password
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.matches_filter(text)
|
35
|
+
filter = @@filter || Rails.application.config.filter_parameters
|
36
|
+
filter.each do |filtered_word|
|
37
|
+
if (@@filter_matchtype == 'fuzzy' and text.include?(filtered_word.to_s)) or
|
38
|
+
(@@filter_matchtype == 'exact' and text == filtered_word.to_s)
|
39
|
+
return true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.get_active_record
|
46
|
+
return ActiveRecord::Base if @@db_username.nil?
|
47
|
+
return @@active_record unless @@active_record.nil?
|
48
|
+
@@active_record = Class.new(ActiveRecord::Base)
|
49
|
+
config = ActiveRecord::Base.connection_config.merge({:username => @@db_username, :password => @@db_password})
|
50
|
+
@@active_record.establish_connection(config)
|
51
|
+
return @@active_record
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.block_expensive_queries?; return @@block_expensive_queries; end
|
55
|
+
def self.max_rows; return @@max_rows; end
|
56
|
+
def self.max_size; return @@max_size; end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module PeriscopeRails
|
2
|
-
class Engine < Rails::Engine
|
3
|
-
end
|
1
|
+
module PeriscopeRails
|
2
|
+
class Engine < Rails::Engine
|
3
|
+
end
|
4
4
|
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
module PeriscopeRails
|
2
|
-
VERSION = "0.0.
|
3
|
-
end
|
1
|
+
module PeriscopeRails
|
2
|
+
VERSION = "0.0.5"
|
3
|
+
end
|
data/periscope_rails.gemspec
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
require File.expand_path("../lib/periscope_rails/version", __FILE__)
|
2
|
-
|
3
|
-
# Provide a simple gemspec so you can easily use your enginex
|
4
|
-
# project in your rails apps through git.
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = "periscope_rails"
|
7
|
-
s.homepage = "http://periscopeapp.herokuapp.com/"
|
8
|
-
s.authors = [ "Tom O'Neill", "Harry Glaser" ]
|
9
|
-
s.email = [ "tom.oneill@live.com", "harry.glaser@gmail.com" ]
|
10
|
-
|
11
|
-
s.summary = "Rails API for Periscope Database Viewer"
|
12
|
-
s.description = "Periscope allows you to query your production database. The gem provides the API for Periscope to communicate with your Rails app."
|
13
|
-
s.files = Dir["{app,lib,config}/**/*"] + ["MIT-LICENSE", "Rakefile", "Gemfile", "README.rdoc"]
|
14
|
-
s.version = "0.0.
|
15
|
-
|
16
|
-
s.add_dependency "activesupport" , "~> 3.0"
|
17
|
-
s.add_dependency "rails" , "~> 3.0"
|
18
|
-
|
19
|
-
s.files = `git ls-files`.split("\n")
|
20
|
-
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
21
|
-
s.require_path = 'lib'
|
22
|
-
end
|
1
|
+
require File.expand_path("../lib/periscope_rails/version", __FILE__)
|
2
|
+
|
3
|
+
# Provide a simple gemspec so you can easily use your enginex
|
4
|
+
# project in your rails apps through git.
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "periscope_rails"
|
7
|
+
s.homepage = "http://periscopeapp.herokuapp.com/"
|
8
|
+
s.authors = [ "Tom O'Neill", "Harry Glaser" ]
|
9
|
+
s.email = [ "tom.oneill@live.com", "harry.glaser@gmail.com" ]
|
10
|
+
|
11
|
+
s.summary = "Rails API for Periscope Database Viewer"
|
12
|
+
s.description = "Periscope allows you to query your production database. The gem provides the API for Periscope to communicate with your Rails app."
|
13
|
+
s.files = Dir["{app,lib,config}/**/*"] + ["MIT-LICENSE", "Rakefile", "Gemfile", "README.rdoc"]
|
14
|
+
s.version = "0.0.5"
|
15
|
+
|
16
|
+
s.add_dependency "activesupport" , "~> 3.0"
|
17
|
+
s.add_dependency "rails" , "~> 3.0"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
21
|
+
s.require_path = 'lib'
|
22
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: periscope_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-05-10 00:00:00.000000000Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
17
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirement: &26545716 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
@@ -22,15 +22,10 @@ dependencies:
|
|
22
22
|
version: '3.0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements:
|
26
|
-
none: false
|
27
|
-
requirements:
|
28
|
-
- - ~>
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
version: '3.0'
|
25
|
+
version_requirements: *26545716
|
31
26
|
- !ruby/object:Gem::Dependency
|
32
27
|
name: rails
|
33
|
-
requirement: !ruby/object:Gem::Requirement
|
28
|
+
requirement: &26545428 !ruby/object:Gem::Requirement
|
34
29
|
none: false
|
35
30
|
requirements:
|
36
31
|
- - ~>
|
@@ -38,12 +33,7 @@ dependencies:
|
|
38
33
|
version: '3.0'
|
39
34
|
type: :runtime
|
40
35
|
prerelease: false
|
41
|
-
version_requirements:
|
42
|
-
none: false
|
43
|
-
requirements:
|
44
|
-
- - ~>
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '3.0'
|
36
|
+
version_requirements: *26545428
|
47
37
|
description: Periscope allows you to query your production database. The gem provides
|
48
38
|
the API for Periscope to communicate with your Rails app.
|
49
39
|
email:
|
@@ -121,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
111
|
version: '0'
|
122
112
|
requirements: []
|
123
113
|
rubyforge_project:
|
124
|
-
rubygems_version: 1.8.
|
114
|
+
rubygems_version: 1.8.10
|
125
115
|
signing_key:
|
126
116
|
specification_version: 3
|
127
117
|
summary: Rails API for Periscope Database Viewer
|