couch_potato-extensions 0.0.1
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/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
|
+
|