couch_potato-extensions 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +33 -0
- data/Rakefile +27 -0
- data/lib/couch_potato/extensions.rb +10 -0
- data/lib/couch_potato/extensions/encrypted_property.rb +46 -0
- data/lib/couch_potato/extensions/encrypted_view_spec.rb +20 -0
- data/lib/couch_potato/extensions/encryption.rb +15 -0
- data/lib/couch_potato/extensions/persistence.rb +10 -0
- data/spec/encrypted_property_spec.rb +49 -0
- data/spec/encrypted_view_spec.rb +36 -0
- data/spec/spec_helper.rb +17 -0
- metadata +108 -0
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
Some additions/extensions to CouchPotato, because awesome needs more awesome.
|
2
|
+
|
3
|
+
### Encrypted attributes
|
4
|
+
|
5
|
+
A simple way to encrypt specific attributes with a specific password and salt.
|
6
|
+
Each attribute can be encrypted differently, by specifying password and salt
|
7
|
+
when declaring them.
|
8
|
+
|
9
|
+
require 'couch_potato'
|
10
|
+
require 'couch_potato/extensions'
|
11
|
+
|
12
|
+
class User
|
13
|
+
include CouchPotato::Persistence
|
14
|
+
include CouchPotato::Extensions::Encryption
|
15
|
+
encrypted\_property :email, :password => "your mum", :salt => "your dad"
|
16
|
+
end
|
17
|
+
|
18
|
+
Of course what's the point if you can't query that stuff? Fret not, help is near:
|
19
|
+
|
20
|
+
class User
|
21
|
+
view :by_email, :key => :email, :type => CouchPotato::Extensions::EncryptedViewSpec
|
22
|
+
end
|
23
|
+
|
24
|
+
CouchPotato.database.view(User.by_email(:key => "paul@example.com"))
|
25
|
+
|
26
|
+
Easy as pie!
|
27
|
+
|
28
|
+
Speaking of easy, so far it's both very simple, because that's what I need, only views
|
29
|
+
with one key are supported so far.
|
30
|
+
|
31
|
+
License: MIT baby!
|
32
|
+
|
33
|
+
Sponsored by [Peritor](http://peritor.com)
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
5
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
6
|
+
end
|
7
|
+
|
8
|
+
NAME='couch_potato-extensions'
|
9
|
+
|
10
|
+
def gemspec_file
|
11
|
+
"#{NAME}.gemspec"
|
12
|
+
end
|
13
|
+
|
14
|
+
def gem_file
|
15
|
+
"#{NAME}-#{source_version}.gem"
|
16
|
+
end
|
17
|
+
|
18
|
+
def source_version
|
19
|
+
line = File.read("lib/#{NAME.gsub(/-/, "/")}.rb")[/^\s*VERSION\s*=\s*.*/]
|
20
|
+
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
21
|
+
end
|
22
|
+
|
23
|
+
task :build do
|
24
|
+
sh "mkdir -p pkg"
|
25
|
+
sh "gem build #{gemspec_file}"
|
26
|
+
sh "mv #{gem_file} pkg"
|
27
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/extensions/persistence")
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/extensions/encryption")
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/extensions/encrypted_property")
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + "/extensions/encrypted_view_spec")
|
5
|
+
|
6
|
+
module CouchPotato
|
7
|
+
module Extensions
|
8
|
+
VERSION = '0.0.1'
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'bcrypt'
|
2
|
+
|
3
|
+
module CouchPotato
|
4
|
+
module Extensions
|
5
|
+
class EncryptedProperty
|
6
|
+
attr_reader :type, :name
|
7
|
+
|
8
|
+
def initialize(owner, name, options = {})
|
9
|
+
@type = owner
|
10
|
+
@name = name
|
11
|
+
@options = options
|
12
|
+
|
13
|
+
define_accessors(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def define_accessors(name)
|
17
|
+
type.class_eval do
|
18
|
+
define_method(name) do
|
19
|
+
instance_variable_get("@#{name}")
|
20
|
+
end
|
21
|
+
|
22
|
+
define_method("#{name}=") do |value|
|
23
|
+
instance_variable_set("@#{name}", value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def build(object, json)
|
29
|
+
value = json[name.to_s].nil? ? json[name.to_sym] : json[name.to_s]
|
30
|
+
object.send "#{name}=", decrypt(value)
|
31
|
+
end
|
32
|
+
|
33
|
+
def serialize(json, object)
|
34
|
+
json[name] = encrypt(object.send(name))
|
35
|
+
end
|
36
|
+
|
37
|
+
def encrypt(value)
|
38
|
+
Base64.encode64(EzCrypto::Key.encrypt_with_password(@options[:password], @options[:salt], value))
|
39
|
+
end
|
40
|
+
|
41
|
+
def decrypt(value)
|
42
|
+
EzCrypto::Key.decrypt_with_password(@options[:password], @options[:salt], Base64.decode64(value))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CouchPotato
|
2
|
+
module Extensions
|
3
|
+
class EncryptedViewSpec < CouchPotato::View::ModelViewSpec
|
4
|
+
|
5
|
+
def view_parameters
|
6
|
+
parameters = super
|
7
|
+
if parameters[:key]
|
8
|
+
parameters[:key] = find_and_encrypt_key_attribute(parameters[:key])
|
9
|
+
end
|
10
|
+
parameters
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_and_encrypt_key_attribute(key)
|
14
|
+
property = klass.properties.find{|property| property.name.to_s == options[:key].to_s}
|
15
|
+
return key if not property
|
16
|
+
property.encrypt(key)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'ezcrypto'
|
2
|
+
|
3
|
+
module CouchPotato
|
4
|
+
module Extensions
|
5
|
+
module Encryption
|
6
|
+
def self.included(base)
|
7
|
+
base.instance_eval do
|
8
|
+
def encrypted_property(name, options = {})
|
9
|
+
properties << CouchPotato::Extensions::EncryptedProperty.new(self, name, options)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CouchPotato::Extensions::EncryptedProperty do
|
4
|
+
class SecureDocument
|
5
|
+
include CouchPotato::Persistence
|
6
|
+
include CouchPotato::Extensions::Encryption
|
7
|
+
encrypted_property :body, :salt => 'Va7JYeT7t08vMweYU6F6dO', :password => "coffee! more coffee!"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "setting up" do
|
11
|
+
it "should add the declared property to the internal list" do
|
12
|
+
SecureDocument.properties.find()
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "accessing attributes" do
|
17
|
+
it "should add attribute accessors" do
|
18
|
+
document = SecureDocument.new
|
19
|
+
document.respond_to?(:body).should == true
|
20
|
+
document.respond_to?(:body=).should == true
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should set the attribute" do
|
24
|
+
document = SecureDocument.new(:body => "very important")
|
25
|
+
document.body.should == 'very important'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "saving documents" do
|
30
|
+
let(:document) { SecureDocument.new(:body => "very important") }
|
31
|
+
|
32
|
+
it "should encrypt the property when accessing the document hash" do
|
33
|
+
body = document.to_hash[:body]
|
34
|
+
body.should_not == nil
|
35
|
+
body.should_not == 'very important'
|
36
|
+
body.should == Base64.encode64(EzCrypto::Key.encrypt_with_password("coffee! more coffee!", "Va7JYeT7t08vMweYU6F6dO", "very important"))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "loading documents" do
|
41
|
+
let(:document) { SecureDocument.new(:body => "very important") }
|
42
|
+
|
43
|
+
it "should decrypt the attributes" do
|
44
|
+
CouchPotato.database.save_document document
|
45
|
+
loaded_document = CouchPotato.database.load_document(document.id)
|
46
|
+
loaded_document.body.should == "very important"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CouchPotato::Extensions::EncryptedViewSpec do
|
4
|
+
class SecureUser
|
5
|
+
include CouchPotato::Persistence
|
6
|
+
include CouchPotato::Extensions::Encryption
|
7
|
+
encrypted_property :email, :salt => 'Va7JYeT7t08vMweYU6F6dO', :password => "coffee! more coffee!"
|
8
|
+
|
9
|
+
view :by_email, :key => :email, :type => CouchPotato::Extensions::EncryptedViewSpec
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
@encrypted_email = Base64.encode64(EzCrypto::Key.encrypt_with_password("coffee! more coffee!", "Va7JYeT7t08vMweYU6F6dO", "paul@example.com"))
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:user) do
|
17
|
+
user = SecureUser.new(:email => "paul@example.com")
|
18
|
+
CouchPotato.database.save_document(user)
|
19
|
+
user
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should encrypt the key before running the view" do
|
23
|
+
CouchPotato.database.send(:database).should_receive(:view) do |url, parameters|
|
24
|
+
parameters[:key].should == @encrypted_email
|
25
|
+
{"rows" => {}}
|
26
|
+
end
|
27
|
+
|
28
|
+
CouchPotato.database.view(SecureUser.by_email(:key => 'paul@example.com'))
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should find documents with an encrypted email" do
|
32
|
+
user
|
33
|
+
results = CouchPotato.database.view(SecureUser.by_email(:key => 'paul@example.com'))
|
34
|
+
results.first.should == user
|
35
|
+
end
|
36
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'couch_potato'
|
4
|
+
|
5
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + "../lib"))
|
6
|
+
|
7
|
+
CouchPotato::Config.database_name = 'couch_potato-extentions_test'
|
8
|
+
def recreate_db
|
9
|
+
CouchPotato.couchrest_database.recreate!
|
10
|
+
end
|
11
|
+
recreate_db
|
12
|
+
|
13
|
+
|
14
|
+
require 'couch_potato/extensions/encryption'
|
15
|
+
require 'couch_potato/extensions/encrypted_property'
|
16
|
+
require 'couch_potato/extensions/persistence'
|
17
|
+
require 'couch_potato/extensions/encrypted_view_spec'
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: couch_potato-extensions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Mathias Meyer
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-04-12 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: couch_potato
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: ezcrypto
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
41
|
+
version: "0"
|
42
|
+
type: :runtime
|
43
|
+
version_requirements: *id002
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: rspec
|
46
|
+
prerelease: false
|
47
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ~>
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
segments:
|
52
|
+
- 1
|
53
|
+
- 2
|
54
|
+
- 9
|
55
|
+
version: 1.2.9
|
56
|
+
type: :development
|
57
|
+
version_requirements: *id003
|
58
|
+
description: See summary, it says it all, trust me.
|
59
|
+
email: meyer@paperplanes.de
|
60
|
+
executables: []
|
61
|
+
|
62
|
+
extensions: []
|
63
|
+
|
64
|
+
extra_rdoc_files:
|
65
|
+
- README.md
|
66
|
+
files:
|
67
|
+
- Rakefile
|
68
|
+
- lib/couch_potato/extensions/encrypted_property.rb
|
69
|
+
- lib/couch_potato/extensions/encrypted_view_spec.rb
|
70
|
+
- lib/couch_potato/extensions/encryption.rb
|
71
|
+
- lib/couch_potato/extensions/persistence.rb
|
72
|
+
- lib/couch_potato/extensions.rb
|
73
|
+
- spec/encrypted_property_spec.rb
|
74
|
+
- spec/encrypted_view_spec.rb
|
75
|
+
- spec/spec_helper.rb
|
76
|
+
- README.md
|
77
|
+
has_rdoc: true
|
78
|
+
homepage: http://github.com/mattmatt/couch_potato-extensions
|
79
|
+
licenses: []
|
80
|
+
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options:
|
83
|
+
- --charset=UTF-8
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
version: "0"
|
100
|
+
requirements: []
|
101
|
+
|
102
|
+
rubyforge_project:
|
103
|
+
rubygems_version: 1.3.6
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: Some extensions for CouchPotato, because more awesome is always a good thing.
|
107
|
+
test_files: []
|
108
|
+
|